Добавить heartbeat и передачу CAN по изменению и таймеру

Для всех Mode передавать пакеты при обновлении данных и повторять каждый через 1300 мс от последнего CAN ACK. Отдельно отправлять heartbeat раз в секунду. Сохранить маски рассылки, отключение потоков нулевым периодом и неблокирующее восстановление после ошибок TX.

Проверены границы периодов, все Mode, занятый mailbox, отмена без CANAA, отсутствие ACK, переполнение Timer1, первый снимок и справедливость потоков. Изменённые модули ecan.c и main.c скомпилированы компилятором TI C2000.
This commit is contained in:
2026-10-16 23:17:00 +03:00
parent 345c81166e
commit 13f1a2c5fd
7 changed files with 351 additions and 120 deletions
+50 -71
View File
@@ -1,8 +1,8 @@
/* Команды и телеметрия eCAN. MBOX1 принимает кадры, MBOX0 передаёт
* технологические регистры, MBOX2 выделен под ответы логгера.
* Слово 127 проходит UMP_commands_write непосредственно в CAN ISR.
* Запрос архива ISR лишь ставит на обслуживание; фрагментация
* ответов выполняется UMP_CAN_service из фонового цикла.
/* Команды и телеметрия eCAN. MBOX1 принимает кадры, MBOX0 передаёт
* технологические регистры, MBOX2 выделен под ответы логгера.
* Слово 127 проходит UMP_commands_write непосредственно в CAN ISR.
* Запрос архива ISR лишь ставит на обслуживание; фрагментация
* ответов выполняется UMP_CAN_service из фонового цикла.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"
@@ -39,9 +39,9 @@ int CanTimeOutErrorTR = 0;
int wait=0;
/* MBOX2 выделен под ответы регистратора; штатный MBOX0 продолжает
* передавать технологические данные независимо. ISR только ставит запрос,
* а снимок и отправка короткими шагами выполняются в основном цикле. */
/* MBOX2 выделен под ответы регистратора; штатный MBOX0 продолжает
* передавать технологические данные независимо. ISR только ставит запрос,
* а снимок и отправка короткими шагами выполняются в основном цикле. */
static volatile unsigned int ump_can_pending;
static volatile unsigned int ump_can_tag, ump_can_address, ump_can_value;
static unsigned int ump_can_reply[UMP_CAN_MAX_WORDS];
@@ -49,6 +49,8 @@ static unsigned int ump_can_length, ump_can_index, ump_can_reply_tag;
static unsigned int ump_can_waiting;
static unsigned long ump_can_sent_at;
#include "can_telemetry_impl.h" /* Определяет heartbeat, подтверждённый кэш и повтор данных через 1,3 с после объявления состояния штатного TX. */
void InitCan(int Port, int DevNum)
{
struct ECAN_REGS ECanShadow;
@@ -59,6 +61,7 @@ void InitCan(int Port, int DevNum)
long id = 0x80BA0000;
CAN_telemetry_init(); /* Сбрасывает кэш, очередь и секундный heartbeat до разрешения аппаратных прерываний. */
DevNum--;
if(DevNum<0)DevNum=0;
if(DevNum>15)DevNum=15;
@@ -86,17 +89,17 @@ void InitCan(int Port, int DevNum)
// Required before writing the MSGIDs
ECanRegs->CANME.all = 0;
// задаем адрес 0 ащикa на передачу
// задаем адрес 0 ащикa на передачу
ECanMboxes->MBOX0.MSGID.all = id + 0x10 + DevNum;
// задаем адрес 1 ащикa на прием
ECanMboxes->MBOX1.MSGID.all = id + DevNum; //поменать!!!! 1 и 0!!!
// задаем адрес 1 ащикa на прием
ECanMboxes->MBOX1.MSGID.all = id + DevNum; //поменать!!!! 1 и 0!!!
// MBOX0 и MBOX2 передают данные; MBOX1 принимает команды.
// MBOX0 и MBOX2 передают данные; MBOX1 принимает команды.
ECanMboxes->MBOX2.MSGID.all = id + 0x20 + DevNum;
ECanRegs->CANMD.all = 0xFFFFFFFA;
// Включаем три mailbox: телеметрия, команды и ответы логгера.
// Включаем три mailbox: телеметрия, команды и ответы логгера.
ECanRegs->CANME.all = 0x00000007;
// Clear all TAn bits
@@ -121,7 +124,7 @@ void InitCan(int Port, int DevNum)
ECanRegs->CANMC.all = ECanShadow.CANMC.all;
while(!ECanRegs->CANES.bit.CCE); // Wait for CCE bit to be set..
// настриваем скорость CAN
// настриваем скорость CAN
ECanShadow.CANBTC.all = ECanRegs->CANBTC.all;
ECanShadow.CANBTC.bit.SJWREG=1;
@@ -134,7 +137,7 @@ void InitCan(int Port, int DevNum)
ECanRegs->CANMC.all = ECanShadow.CANMC.all;
while(ECanRegs->CANES.bit.CCE); // Wait for CCE bit to be cleared..
// задаем таймауты дла ожиданиа отправки получениа посылки
// задаем таймауты дла ожиданиа отправки получениа посылки
ECanMOTORegs->MOTO0 = 550000;
ECanMOTORegs->MOTO1 = 550000;
@@ -161,7 +164,7 @@ void InitCan(int Port, int DevNum)
IER |= M_INT9; // Enable CPU INT
EDIS;
// завершили настройку CAN ащиков
// завершили настройку CAN ащиков
MessageReceivedCount = 0;
ErrorCount = 0;
@@ -169,43 +172,10 @@ void InitCan(int Port, int DevNum)
MessageTransivedCount=0;
}
/* При занятом MBOX0 возвращается без ожидания ACK в цикле.
* Это отличается от блокирующих UART/EEPROM операций main.
/* При занятом MBOX0 возвращается без ожидания ACK в цикле.
* Это отличается от блокирующих UART/EEPROM операций main.
*/
void CAN_send(int Port, int data[], int Addr)
{
unsigned long hiword,loword;
volatile struct ECAN_REGS * ECanRegs;
volatile struct ECAN_MBOXES * ECanMboxes;
ECanRegs = &ECanaRegs;
ECanMboxes = &ECanaMboxes;
if(wait)
if(!(ECanRegs->CANTA.all & 1))
if(!(ECanRegs->CANAA.all & 1))
return;
ECanRegs->CANTA.all = 1;
ECanRegs->CANAA.all = 1;
hiword= ((((Uint32) Addr ) & 0xffff)<<16)| 0xE0000000 |
((((Uint32)data[Addr ]) & 0xffff) );
loword= ((((Uint32)data[Addr+1]) & 0xffff)<<16)|
((((Uint32)data[Addr+2]) & 0xffff) );
ECanMboxes->MBOX0.MDH.all = hiword;
ECanMboxes->MBOX0.MDL.all = loword;
EALLOW;
ECanRegs->CANTSC = 0; // clear time-out counter
EDIS;
ECanRegs->CANTRS.all = 1; // запустить передачу
wait=1;
led1_toggle();
}
/* CAN_send определён общим для этой единицы трансляции блоком can_telemetry_impl.h выше. */
void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
@@ -220,9 +190,9 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
hiword = ECanMboxes->MBOX1.MDH.all;
loword = ECanMboxes->MBOX1.MDL.all;
/* Служебный запрос логгера не является командой УМП и сам не должен
* заполнять журнал CAN-событиями при онлайн-чтении. Короткие кадры
* отбрасываются: незаполненные байты mailbox могли остаться от прошлого. */
/* Служебный запрос логгера не является командой УМП и сам не должен
* заполнять журнал CAN-событиями при онлайн-чтении. Короткие кадры
* отбрасываются: незаполненные байты mailbox могли остаться от прошлого. */
if ((unsigned int)(hiword >> 16) == UMP_CAN_MARKER) {
if (ECanMboxes->MBOX1.MSGCTRL.bit.DLC == 8) {
ump_can_tag = (unsigned int)hiword;
@@ -244,10 +214,10 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
Data[1] = (loword>>16) & 0xffff;
Data[2] = (loword ) & 0xffff;
/* Каждое разрешённое слово имеет собственный адрес. Не опрашиваем
* Commands после кадра безусловно: пакет телеметрии не должен
* превращать внутренний сброс параметров в командный фронт.
* Адрес 127 проходит через единый обработчик полного слова. */
/* Каждое разрешённое слово имеет собственный адрес. Не опрашиваем
* Commands после кадра безусловно: пакет телеметрии не должен
* превращать внутренний сброс параметров в командный фронт.
* Адрес 127 проходит через единый обработчик полного слова. */
{
unsigned int i;
for (i = 0; i < 3; i++, adr++) {
@@ -258,7 +228,7 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
}
}
/* Фиксируем применённую команду до выхода из обработчика CAN. */
/* Фиксируем применённую команду до выхода из обработчика CAN. */
ump_log_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);
led2_toggle();
}
@@ -292,8 +262,17 @@ interrupt void CANa_reset_err(void)
PieCtrlRegs.PIEACK.all = 0xFFFF; // Enable PIE interrupts
EINT;
ECanaRegs.CANTRR.all = 1;
CanTimeOutErrorTR++;
/* Проверяет реальный тайм-аут mailbox 0: отложенное PIE-прерывание после успешного TX уже может не иметь причины. */
if (ECanaRegs.CANTOS.all & 1UL)
{ /* Обрабатывает только штатный передатчик; служебный mailbox 2 контролируется отдельно в UMP_CAN_service. */
EALLOW; /* Разрешает изменение управляющего регистра eCAN перед снятием источника прерывания. */
ECanaRegs.CANTOC.all &= ~1UL; /* Снимает timeout только mailbox 0, сохраняя контроль служебных передач. */ /* Сброс TOC снимает TOS и MTOF согласно SPRUI07, 13.8.18.3; одной отмены TX недостаточно. */
EDIS; /* Восстанавливает защиту регистров до выхода из ветви обработки тайм-аута. */
if (ECanaRegs.CANTRS.all & 1UL) /* Передача могла завершиться между чтением TOS и снятием контроля. */
ECanaRegs.CANTRR.all = 1UL; /* Запрашивает отмену только ещё занятого mailbox 0, не задерживая прерывание ожиданием CANAA. */
can_tx_failed = 1U; /* Не допускает записи повреждённого или отменённого кадра в подтверждённый кэш телеметрии. */
CanTimeOutErrorTR++; /* Считает обнаруженный тайм-аут один раз, исключая фантомные повторные входы PIE. */
} /* Следующая штатная передача сама заново включит TOC после сброса временного счётчика. */
PieCtrlRegs.PIEACK.bit.ACK9 |= 1;
@@ -307,10 +286,10 @@ interrupt void CANa_reset_err(void)
//===========================================================================
/* Один вызов обслуживает максимум один кадр и никогда не ждёт ACK в цикле.
* Снимок фиксируется один раз на запрос: CAN-фрагменты не смешивают
* значения до/после переключения кольцевого банка. Новые запросы забираем
* после завершения предыдущего ответа. GUI держит только один запрос. */
/* Один вызов обслуживает максимум один кадр и никогда не ждёт ACK в цикле.
* Снимок фиксируется один раз на запрос: CAN-фрагменты не смешивают
* значения до/после переключения кольцевого банка. Новые запросы забираем
* после завершения предыдущего ответа. GUI держит только один запрос. */
void UMP_CAN_service(void)
{
unsigned int saved, tag, address, value, error;
@@ -321,11 +300,11 @@ void UMP_CAN_service(void)
ump_can_waiting = 0;
} else if ((ECanaRegs.CANAA.all & 4UL) ||
((unsigned long)CpuTimer1.InterruptCount - ump_can_sent_at > 250UL)) {
/* Нет подтверждения шины: отменяем только служебный mailbox.
* GUI обнаружит неполный ответ по тайм-ауту; управление MBOX0
* и приём команд MBOX1 продолжаются. */
/* Нет подтверждения шины: отменяем только служебный mailbox.
* GUI обнаружит неполный ответ по тайм-ауту; управление MBOX0
* и приём команд MBOX1 продолжаются. */
ECanaRegs.CANTRR.all = 4UL;
/* До фактического завершения отмены mailbox не переиспользуем. */
/* До фактического завершения отмены mailbox не переиспользуем. */
if (!(ECanaRegs.CANAA.all & 4UL)) return;
ECanaRegs.CANAA.all = 4UL;
ump_can_waiting = 0;
@@ -342,7 +321,7 @@ void UMP_CAN_service(void)
__restore_interrupts(saved);
}
if (ump_can_index >= ump_can_length) return;
/* Перед следующим фрагментом уступаем штатной телеметрии MBOX0. */
/* Перед следующим фрагментом уступаем штатной телеметрии MBOX0. */
if (ECanaRegs.CANTRS.all & 1UL) return;
hiword = ((unsigned long)(UMP_CAN_MARKER + ump_can_index/2) << 16) | ump_can_reply_tag;
loword = ((unsigned long)ump_can_reply[ump_can_index] << 16) | ump_can_reply[ump_can_index+1];