feat: add M95M02-only GAS and EEPROM profiles
Expose the existing registers through Modbus and service CAN using one GAS provider only in M95M02 builds. Include the EEPROM layout/driver, LOAD protection and calibration, firmware identity and shared CCS build workflow. Add transport/profile and SCI8 validation tests, documentation and the checked M95M02 firmware image.
This commit is contained in:
@@ -21,12 +21,110 @@ unsigned long WAKEpowse;
|
||||
unsigned long IMPowse;
|
||||
unsigned int period_dac, time_dac;
|
||||
|
||||
/* Âñå âûõîäû ÓÌÏ è ðàìïà ïðèíàäëåæàò îäíîìó îáðàáîò÷èêó Timer1.
|
||||
* Îñíîâíîé öèêë áîëüøå íå âûäà¸ò START: èíà÷å îí ìîæåò óâèäåòü êîðîòêèé
|
||||
* ñïàä êîìàíäû, êîòîðûé ïðîïóñòèò ðàñ÷¸ò ÖÀÏ ñ ïåðèîäîì 5 ìñ. */
|
||||
#define LOAD_IDLE 0U
|
||||
#define LOAD_RUN 1U
|
||||
#define LOAD_RELOAD 2U
|
||||
#define LOAD_FAULT 3U
|
||||
#define LOAD_MAX_ATTEMPTS 5U
|
||||
#define LOAD_VOLTAGE_MIN 30U
|
||||
#define LOAD_PULSE_MS 1000U
|
||||
static unsigned int load_state, load_attempts, load_inhibit;
|
||||
static unsigned int load_count_dac, load_count_ramp, load_init_count;
|
||||
static unsigned int load_zero_sent, load_stop_asserted, load_initialized;
|
||||
static float load_go, load_end;
|
||||
/* 16-áèòíûå ïîëÿ îáùèå ñ CAN ISR. Ñíèìîê è óâåëè÷åíèå âîçðàñòà âûïîëíÿþòñÿ
|
||||
* ïîä êîðîòêîé áëîêèðîâêîé IRQ; îòïðàâêà SPI ïîä áëîêèðîâêîé íå âûïîëíÿåòñÿ. */
|
||||
static volatile unsigned int load_voltage, load_voltage_age, load_voltage_seen;
|
||||
static volatile unsigned int load_simulation;
|
||||
|
||||
void Load_control_init(void)
|
||||
{
|
||||
load_state = LOAD_IDLE; load_attempts = 0; load_inhibit = 0;
|
||||
load_count_dac = 0; load_count_ramp = 0; load_init_count = 1;
|
||||
load_zero_sent = 0; load_stop_asserted = 0; load_initialized = 0;
|
||||
load_go = 0; load_end = 0;
|
||||
load_voltage = 0; load_voltage_age = 0; load_voltage_seen = 0;
|
||||
load_simulation = 0;
|
||||
IMPowse = 0; WAKEpowse = 0; period_dac = 0; time_dac = 0;
|
||||
}
|
||||
|
||||
/* Âîçðàñò ñáðàñûâàåò òîëüêî íóæíîå íàïðÿæåíèå, à íå ëþáîé CAN-ïàêåò.
|
||||
* ÓÌÏ 5: ÇÏÒ1, èíäåêñ 305; ÓÌÏ 6: ÇÏÒ2, èíäåêñ 8. Ìàñøòàá 1 Â/åä.
|
||||
* Ìàñêè ñëîòîâ ñîõðàíÿþò àäðåñà äàæå äëÿ ïðîïóùåííûõ ñëîâ êàäðà. */
|
||||
void Load_voltage_can(unsigned int header, unsigned int a,
|
||||
unsigned int b, unsigned int c)
|
||||
{
|
||||
unsigned int address = header & 0x1FFFU;
|
||||
unsigned int selected, i, mask = 0x8000U, data[3];
|
||||
if (Desk != dsk_LOAD || (load_simulation & 1U)) return;
|
||||
if (Mode == adr_LOA1) selected = 305U;
|
||||
else if (Mode == adr_LOA2) selected = 8U;
|
||||
else return;
|
||||
data[0] = a; data[1] = b; data[2] = c;
|
||||
for (i = 0; i < 3; i++, address++, mask >>= 1) {
|
||||
if ((header & mask) && address == selected) {
|
||||
load_voltage = data[i];
|
||||
load_voltage_age = 0;
|
||||
load_voltage_seen = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* STOP óäåðæèâàåòñÿ âåñü ñáðîñ, âêëþ÷àÿ îòïðàâêó êîäà 4 ìÀ â ÖÀÏ.
|
||||
* Ïîâòîðíûé ïóñê ðàçðåø¸í òîëüêî ïîñëå ýòîé îòïðàâêè è 1000 ìñ STOP.
|
||||
* Ýòî ïîäòâåðæäåíèå ïðîãðàììíîé îòïðàâêè, íå èçìåðåíèå ôèçè÷åñêîãî òîêà. */
|
||||
static void load_stop(unsigned int state)
|
||||
{
|
||||
clear_START_DPTB();
|
||||
set_STOP_DPTB();
|
||||
clear_RES_OUT_2();
|
||||
load_stop_asserted = 1;
|
||||
load_state = state;
|
||||
load_count_ramp = 0;
|
||||
load_zero_sent = 0;
|
||||
IMPowse = LOAD_PULSE_MS;
|
||||
}
|
||||
|
||||
static void load_start(void)
|
||||
{
|
||||
/* Óñòàâêè ôèêñèðóþòñÿ äëÿ êàæäîé ïîïûòêè. Âíóòðåííèé íîëü = 4 ìÀ.
|
||||
* Èñïðàâëåíà îïå÷àòêà ñòàðîãî îãðàíè÷åíèÿ: îãðàíè÷èâàåì êîíåö ðàìïû,
|
||||
* à íå çàìåíÿåì íà÷àëüíóþ óñòàâêó íà 16 (÷òî äàâàëî ñêà÷îê äî 20 ìÀ). */
|
||||
load_go = (float)DAC_go - 4.0;
|
||||
load_end = (float)DAC_stop - 4.0;
|
||||
if (load_go < 0) load_go = 0;
|
||||
if (load_go > 5) load_go = 5;
|
||||
if (load_end > 16) load_end = 16;
|
||||
if (load_end <= load_go) load_end = load_go + 1;
|
||||
ump_dac_go10 = (unsigned int)((load_go + 4.0) * 10.0);
|
||||
ump_dac_stop10 = (unsigned int)((load_end + 4.0) * 10.0);
|
||||
load_count_ramp = 0;
|
||||
load_attempts++;
|
||||
/* STOP îòïóñêàåì íåïîñðåäñòâåííî ïåðåä START, ðàçðåøåíèå — ïîñëå íåãî.
|
||||
* Çàäàíèå îñòà¸òñÿ 4 ìÀ äî ïåðâîãî øàãà íîâîé ðàìïû. */
|
||||
clear_STOP_DPTB();
|
||||
load_stop_asserted = 0;
|
||||
set_START_DPTB();
|
||||
set_RES_OUT_2();
|
||||
IMPowse = LOAD_PULSE_MS;
|
||||
load_state = LOAD_RUN;
|
||||
}
|
||||
|
||||
void Setup_DAC_time(void)
|
||||
{
|
||||
WAKEpowse = 3L * DAC_FREQ +1;
|
||||
|
||||
period_dac = READY_FREQ / DAC_FREQ;
|
||||
time_dac = LOAD_TIME * DAC_FREQ;
|
||||
/* Ñòàðûå EEPROM èìåþò íîëü â íîâîì ïàðàìåòðå: èñïîëüçóåì 600 ìñ.
|
||||
* 1..60000 ìñ ìîæíî ìåíÿòü ÷åðåç ðåãèñòð 0x52 è ñîõðàíÿòü øòàòíî. */
|
||||
if ((unsigned int)LOAD_CAN_TIMEOUT == 0U ||
|
||||
(unsigned int)LOAD_CAN_TIMEOUT > 60000U) LOAD_CAN_TIMEOUT = 600;
|
||||
LOAD_STATUS = 0; LOAD_ATTEMPTS = 0;
|
||||
load_initialized = 1;
|
||||
}
|
||||
|
||||
void dOUT(int x)
|
||||
@@ -63,7 +161,7 @@ void Init_DAC(void)
|
||||
toggle_RES_OUT_1();
|
||||
}
|
||||
|
||||
void Anal_output(long vrot, long maxx)
|
||||
static void anal_output(long vrot, long maxx, int calibration)
|
||||
{
|
||||
long out;
|
||||
static int x;
|
||||
@@ -72,7 +170,7 @@ void Anal_output(long vrot, long maxx)
|
||||
|
||||
x=0;// !x; òùåòíî áûòèå
|
||||
|
||||
if(cCalibrDac) out=DAC_cal();
|
||||
if(calibration && cCalibrDac) out=DAC_cal();
|
||||
|
||||
out = out & 0xFFF;
|
||||
|
||||
@@ -99,79 +197,145 @@ Log_to_mem(modbus[0x1D]);
|
||||
|
||||
}
|
||||
|
||||
void Load_runner()
|
||||
/* Ñîõðàí¸í ïóáëè÷íûé èíòåðôåéñ; çàùèòíûé ñáðîñ âûçûâàåò âíóòðåííþþ
|
||||
* ôóíêöèþ ñ calibration=0, ÷òîáû ðó÷íàÿ êàëèáðîâêà íå ïîäìåíèëà 4 ìÀ. */
|
||||
void Anal_output(long vrot, long maxx)
|
||||
{
|
||||
static unsigned int count_dac=0, count_load=0, x=1;
|
||||
static unsigned int preStart=0;
|
||||
static float dac_go,dac_stop;
|
||||
float sinus=0;
|
||||
int kod;
|
||||
if (maxx > 0) anal_output(vrot, maxx, 1);
|
||||
}
|
||||
|
||||
if(IMPowse) IMPowse--;
|
||||
if(++count_dac >= period_dac)
|
||||
{
|
||||
count_dac=0;
|
||||
void Load_runner(void)
|
||||
{
|
||||
unsigned int saved, commands, voltage, fresh, timeout;
|
||||
unsigned int start, reset, active = 0;
|
||||
float sinus = 0;
|
||||
|
||||
if(WAKEpowse)
|
||||
{
|
||||
--WAKEpowse;
|
||||
/* ISR ðàáîòàåò 1 êÃö, íî GPIO/ÖÀÏ íåëüçÿ îáñëóæèâàòü äî çàãðóçêè
|
||||
* ïàðàìåòðîâ. Ýòî òàêæå èñêëþ÷àåò ïðåæíåå äåëåíèå íà time_dac=0. */
|
||||
if (!load_initialized || !READY || !period_dac || !time_dac) return;
|
||||
saved = __disable_interrupts();
|
||||
commands = (unsigned int)Commands;
|
||||
voltage = (load_simulation & 2U) ? 0U : load_voltage;
|
||||
timeout = (unsigned int)LOAD_CAN_TIMEOUT;
|
||||
if (!timeout || timeout > 60000U) timeout = 600U;
|
||||
/* Äî ïåðâîãî ïàêåòà çíà÷åíèå 0 íå ñ÷èòàåòñÿ ñâåæèì èçìåðåíèåì.
|
||||
* Íàñûùåíèå âîçðàñòà èñêëþ÷àåò ëîæíîå âîññòàíîâëåíèå ïîñëå ïåðåïîëíåíèÿ. */
|
||||
fresh = load_voltage_seen && load_voltage_age < timeout;
|
||||
if (load_voltage_age < 65535U) load_voltage_age++;
|
||||
__restore_interrupts(saved);
|
||||
start = commands & 0x80U; reset = commands & 0x40U;
|
||||
if (IMPowse) IMPowse--;
|
||||
|
||||
if( (WAKEpowse == DAC_FREQ/2*6)||
|
||||
(WAKEpowse == DAC_FREQ/2*5)||
|
||||
(WAKEpowse == DAC_FREQ/2*4)||
|
||||
(WAKEpowse == DAC_FREQ/2*3)||
|
||||
(WAKEpowse == DAC_FREQ/2*2)||
|
||||
(WAKEpowse == DAC_FREQ/2*1) )
|
||||
{
|
||||
Init_DAC(); x=1;
|
||||
} }
|
||||
/* Îòñóòñòâèå êîìàíäû ïóñêà — íà÷àëî íîâîãî ñåàíñà, ñáðàñûâàåò îøèáêó.
|
||||
* RESET âñåãäà ñòàðøå START; îòïóñêàíèå RESET ïðè îñòàâøåìñÿ START
|
||||
* íå äà¸ò íåîæèäàííîãî ïîâòîðíîãî ïóñêà: ñíà÷àëà òðåáóåòñÿ START=0. */
|
||||
if (!start) {
|
||||
if (load_state != LOAD_IDLE) load_stop(LOAD_IDLE);
|
||||
load_attempts = 0; load_inhibit = 0;
|
||||
} else if (reset) {
|
||||
if (load_state != LOAD_FAULT && load_state != LOAD_IDLE)
|
||||
load_stop(LOAD_IDLE);
|
||||
load_inhibit = 1;
|
||||
}
|
||||
if (reset && !load_stop_asserted) load_stop(LOAD_IDLE);
|
||||
|
||||
else
|
||||
{
|
||||
if(cUMPstart)
|
||||
{
|
||||
if(!preStart)
|
||||
{
|
||||
dac_go=DAC_go-4;
|
||||
dac_stop=DAC_stop-4;
|
||||
if(dac_go<0) dac_go=0;
|
||||
if(dac_go>5) dac_go=5;
|
||||
if(dac_stop>16) dac_go=16;
|
||||
if(dac_stop<=dac_go) dac_stop=dac_go+1;
|
||||
/* Äëÿ ëîãà ñîõðàíÿåì ðåàëüíûå îãðàíè÷åííûå óñòàâêè:
|
||||
* âíóòðåííèå dac_go/stop îòñ÷èòûâàþòñÿ îò 4 ìÀ. */
|
||||
ump_dac_go10 = (unsigned int)((dac_go + 4.0) * 10.0);
|
||||
ump_dac_stop10 = (unsigned int)((dac_stop + 4.0) * 10.0);
|
||||
}
|
||||
/* Ïîâòîðíûé START äîïóñêàåòñÿ ïîñëå ñáðîñà ÖÀÏ, îêîí÷àíèÿ STOP è
|
||||
* âîññòàíîâëåíèÿ íóæíîãî CAN-íàïðÿæåíèÿ. Òàéìàóò ñàì íå òðàòèò ïîïûòêó. */
|
||||
if (start && !reset && !load_inhibit && !WAKEpowse && fresh &&
|
||||
load_zero_sent && !IMPowse &&
|
||||
(load_state == LOAD_IDLE || load_state == LOAD_RELOAD)) load_start();
|
||||
if (load_state == LOAD_RUN && !IMPowse) clear_START_DPTB();
|
||||
|
||||
if(count_load > (time_dac/2))count_load++;
|
||||
|
||||
if(++count_load > time_dac) count_load = time_dac;
|
||||
|
||||
sinus = ((dac_stop - dac_go) / 16.0 * count_load) + (dac_go / 16.0 * time_dac);
|
||||
|
||||
// sinus = (10.0 / 16.0 * count_load) + (2.0 / 16.0 * time_dac);
|
||||
}
|
||||
else
|
||||
{ count_load = 0;
|
||||
sinus=0;
|
||||
x = (x+1)&0x3FF;
|
||||
}
|
||||
|
||||
/* Ñíèìîê ñòàäèè ðàçãîíà äëÿ ñîïîñòàâëåíèÿ êîìàíäû CAN,
|
||||
* îæèäàåìîãî òîêà è êîäà, äåéñòâèòåëüíî îòïðàâëåííîãî ÖÀÏ. */
|
||||
ump_dac_ramp = count_load;
|
||||
if (++load_count_dac >= period_dac) {
|
||||
load_count_dac = 0;
|
||||
if (WAKEpowse) {
|
||||
--WAKEpowse;
|
||||
if (WAKEpowse && !(WAKEpowse % (DAC_FREQ / 2))) {
|
||||
Init_DAC(); load_init_count = 1;
|
||||
}
|
||||
} else {
|
||||
active = load_state == LOAD_RUN;
|
||||
if (active) {
|
||||
/* Ïðè òàéìàóòå ñîõðàíÿåì ïîëîæåíèå È îòïðàâëåííîå çàäàíèå,
|
||||
* íå äåëàåì STOP è íå ïðîäîëæàåì ðàçãîí áåç îáðàòíîé ñâÿçè. */
|
||||
if (fresh) {
|
||||
if (load_count_ramp > time_dac / 2) load_count_ramp++;
|
||||
if (++load_count_ramp > time_dac) load_count_ramp = time_dac;
|
||||
}
|
||||
sinus = ((load_end - load_go) / 16.0 * load_count_ramp) +
|
||||
(load_go / 16.0 * time_dac);
|
||||
/* Ïðîâåðÿåì ñëåäóþùèé øàã ÄÎ ïåðåäà÷è ÖÀÏ. 6 ìÀ äîïóñòèìû,
|
||||
* ñòðîãî >6 ìÀ è <30  òðåáóþò íåìåäëåííîãî STOP.
|
||||
* Ïåðâàÿ ïîïûòêà âõîäèò â ëèìèò 5; øåñòîãî START íå áóäåò. */
|
||||
if (fresh && voltage < LOAD_VOLTAGE_MIN &&
|
||||
sinus * 16.0 > 2.0 * time_dac) {
|
||||
load_stop(load_attempts >= LOAD_MAX_ATTEMPTS ?
|
||||
LOAD_FAULT : LOAD_RELOAD);
|
||||
active = 0; sinus = 0;
|
||||
}
|
||||
} else {
|
||||
load_count_ramp = 0;
|
||||
load_init_count = (load_init_count + 1) & 0x3FFU;
|
||||
}
|
||||
/* Âî âðåìÿ çàùèòû è ïóñêà ðó÷íîé êîä êàëèáðîâêè çàïðåù¸í.
|
||||
* Êàëèáðîâêà ñîõðàíåíà òîëüêî ïðè ñíÿòîì START è ñâîáîäíîì STOP.
|
||||
* Íóëåâîé êîä çàäàíèÿ çäåñü îçíà÷àåò òîê 4 ìÀ ïî DAC_min(). */
|
||||
ump_dac_ramp = load_count_ramp;
|
||||
ump_dac_duration = time_dac;
|
||||
ump_dac_position = (unsigned int)sinus;
|
||||
preStart = cUMPstart;
|
||||
if (active && !fresh) {
|
||||
/* Óäåðæèâàåì ÖÀÏ. Äàæå cInitDac íå ìåíÿåò òîê â ïàóçå CAN. */
|
||||
} else if ((!load_init_count || cInitDac) && !load_stop_asserted) {
|
||||
Init_DAC(); load_init_count = 1; cInitDac = 0;
|
||||
} else {
|
||||
anal_output((int)sinus, time_dac,
|
||||
!start && !load_stop_asserted);
|
||||
/* A manual calibration frame is not a confirmed 4 mA reload.
|
||||
* START must wait for a forced baseline frame after it. */
|
||||
if (!active) load_zero_sent = !(!start && !load_stop_asserted && cCalibrDac);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Äèàãíîñòèêà äîñòóïíà îáû÷íûì Modbus/CAN, íåçàâèñèìî îò ëîããåðà:
|
||||
* áèò 0 — îøèáêà ïÿòè ïóñêîâ; áèò 1 — íåò ñâåæåãî íàïðÿæåíèÿ;
|
||||
* áèò 2 — ñáðîñ ïåðåä ïîâòîðîì; áèò 3 — ðàáîòà ðàìïû.
|
||||
* Îøèáêà óäåðæèâàåòñÿ ñî STOP, ïîêà îïåðàòîð íå ñíèìåò START. */
|
||||
LOAD_STATUS = (load_state == LOAD_FAULT ? 1U : 0U) |
|
||||
(!fresh ? 2U : 0U) |
|
||||
(load_state == LOAD_RELOAD ? 4U : 0U) |
|
||||
(load_state == LOAD_RUN ? 8U : 0U) |
|
||||
(load_simulation << 4);
|
||||
LOAD_ATTEMPTS = load_attempts;
|
||||
}
|
||||
|
||||
if(!x || cInitDac)
|
||||
{
|
||||
Init_DAC(); x=1; cInitDac=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
kod = (int)sinus;
|
||||
|
||||
Anal_output(kod, time_dac);
|
||||
} } } }
|
||||
/* Local versioned block, shared by RTU and service CAN. Probe its signature
|
||||
* before writes: old firmware returns exception 2 instead of starting tests.
|
||||
* Simulation is RAM-only, zeroed at boot, and never copied into EEPROM.
|
||||
* bit 0 ignores ZPT reception (age reaches the configured timeout);
|
||||
* bit 1 substitutes 0 V only for protection, leaving real logged CAN intact. */
|
||||
unsigned int Load_protection_prepare(unsigned int function, unsigned int address,
|
||||
unsigned int value, unsigned int *out, unsigned int *error)
|
||||
{
|
||||
unsigned int saved = __disable_interrupts();
|
||||
*error = 2;
|
||||
if (Desk == dsk_LOAD && address == 0x1300U && function == 3 && value == 8) {
|
||||
out[0] = 0x5550U; out[1] = 1;
|
||||
out[2] = load_simulation; out[3] = (unsigned int)LOAD_CAN_TIMEOUT;
|
||||
out[4] = (unsigned int)LOAD_STATUS; out[5] = load_attempts;
|
||||
out[6] = load_voltage; out[7] = load_voltage_seen ? load_voltage_age : 65535U;
|
||||
*error = 0;
|
||||
__restore_interrupts(saved);
|
||||
return 8;
|
||||
}
|
||||
if (Desk == dsk_LOAD && function == 6) {
|
||||
if (address == 0x1302U && value <= 3U) {
|
||||
load_simulation = value;
|
||||
*error = 0;
|
||||
} else if (address == 0x1303U && value >= 1U && value <= 60000U) {
|
||||
LOAD_CAN_TIMEOUT = value; *error = 0;
|
||||
} else if (address == 0x1302U || address == 0x1303U) *error = 3;
|
||||
}
|
||||
out[0] = address; out[1] = value;
|
||||
__restore_interrupts(saved);
|
||||
return 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user