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:
@@ -1,5 +1,5 @@
|
||||
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
|
||||
#include "DSP2833x_Examples.h" // DSP281x Examples Include File
|
||||
#include "DSP2833x_Examples.h" // DSP281x Examples Include File
|
||||
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
||||
|
||||
#include "ADC.h"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -6,3 +6,13 @@ void Setup_DAC_time(void);
|
||||
/* Ñ÷¸ò÷èê ïóñêîâîãî èìïóëüñà è âûäåðæêè èíèöèàëèçàöèè äîñòóïíû ëîããåðó. */
|
||||
extern unsigned long IMPowse, WAKEpowse;
|
||||
extern unsigned int period_dac, time_dac;
|
||||
|
||||
/* Call once before IRQ; complete technological CAN packets update voltage. */
|
||||
void Load_control_init(void);
|
||||
void Load_voltage_can(unsigned int header, unsigned int a,
|
||||
unsigned int b, unsigned int c);
|
||||
|
||||
/* 0x1300/8 words: signature, version, simulation, timeout, status, attempts,
|
||||
* voltage, age. Only 0x1302 (simulation) and 0x1303 (timeout) are writable. */
|
||||
unsigned int Load_protection_prepare(unsigned int function, unsigned int address,
|
||||
unsigned int value, unsigned int *out, unsigned int *error);
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
4876, 5005, 4876, 4847, 1898, 1873, 2535, 2502, // Áîðò 1
|
||||
|
||||
// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I
|
||||
3820, 3790, 3505, 3380, 1736, 683, 854, 14, // Αξπς 0 1062 1980
|
||||
3835, 3785, 3522, 3332, 1745, 689, 860, 17, // Αξπς 1 1720 2405
|
||||
7580, 7540, 2310, 2420, 1736, 683, 854, 14, // Αξπς 0 1062 1980
|
||||
7580, 7540, 2310, 2420, 1745, 689, 860, 17, // Αξπς 1 1720 2405
|
||||
|
||||
// ÁÊÑÑÄ 100 Ohm 150 Ohm
|
||||
1281, 1272, 0, 0, 622, 2263, 0, 0,
|
||||
|
||||
15
Source/Internal/Include/eeprom_config.h
Normal file
15
Source/Internal/Include/eeprom_config.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef BALSAM167_EEPROM_CONFIG_H
|
||||
#define BALSAM167_EEPROM_CONFIG_H
|
||||
/* Build-time checkbox: 0 = AT25256B (32 KiB), 1 = M95M02-DR (256 KiB).
|
||||
* This must match the soldered part BEFORE startup loads saved parameters.
|
||||
* CCS: change the value below, then Project > Clean and Rebuild.
|
||||
* Command-line builds may override EEPROM_M95M02 for that build only.
|
||||
* A GUI checkbox cannot change SPI ROM boot or startup initialization.
|
||||
*/
|
||||
#ifndef EEPROM_M95M02
|
||||
#define EEPROM_M95M02 0
|
||||
#endif
|
||||
#if EEPROM_M95M02 != 0 && EEPROM_M95M02 != 1
|
||||
#error EEPROM_M95M02_must_be_0_or_1
|
||||
#endif
|
||||
#endif
|
||||
28
Source/Internal/Include/gas167.h
Normal file
28
Source/Internal/Include/gas167.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef BALSAM167_GAS_H
|
||||
#define BALSAM167_GAS_H
|
||||
#include "eeprom_config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Board profile 167/v1, word addresses, independent of the wire transport.
|
||||
* The original register and UMP addresses remain valid in both builds.
|
||||
* Only the physically fitted M95M02 version exposes the additional regions. */
|
||||
#if EEPROM_M95M02
|
||||
#define GAS167_REG_BASE 0x5000U
|
||||
#define GAS167_REG_COUNT 128U
|
||||
#define GAS167_INFO_BASE 0x5F00U
|
||||
#define GAS167_INFO_WORDS 8U
|
||||
#define GAS167_MAX_WORDS 124U
|
||||
#define GAS167_PROFILE_VERSION 1U
|
||||
#define GAS167_CAPABILITIES 7U /* bit 0 RTU, bit 1 service CAN, bit 2 FC06 */
|
||||
|
||||
/* Called by the main-loop transports under their snapshot IRQ lock.
|
||||
* Capacity: at least GAS167_MAX_WORDS uint16_t words.
|
||||
* RTU reads: 1..124 words; paired service CAN reads: 2..124, even.
|
||||
* Successful reads return their count. Writes/errors return address/value.
|
||||
* error uses Modbus codes 0 (success), 1 (function), 2 (address), 3 (value).
|
||||
* No EEPROM I/O, allocation, or changes to the existing logger. */
|
||||
int gas167_contains(uint16_t address);
|
||||
unsigned gas167_prepare(unsigned function, uint16_t address, uint16_t value,
|
||||
int can, uint16_t *reply, unsigned *error);
|
||||
#endif
|
||||
#endif
|
||||
@@ -95,6 +95,11 @@
|
||||
#define DAC_go modbus[0x50] // íà÷àëî çàðàäà
|
||||
#define DAC_stop modbus[0x51] // êîíåö çàðàäà
|
||||
|
||||
/* LOAD-only persistent CAN timeout (ms), read-only status and attempts. */
|
||||
#define LOAD_CAN_TIMEOUT modbus[0x52]
|
||||
#define LOAD_STATUS modbus[0x7C]
|
||||
#define LOAD_ATTEMPTS modbus[0x7D]
|
||||
|
||||
#define Cancount (modbus+0x60) // ïàóçà ìåæäó I ïîñûëêàìè CAN
|
||||
#define Bright (modbus+0x62) // àðêîñòü ñèãíàëüíûõ ëàìïî÷åê
|
||||
#define Brightness modbus[0x62] // àðêîñòü ñèãíàëüíûõ ëàìïî÷åê
|
||||
|
||||
@@ -2,8 +2,19 @@
|
||||
|
||||
#define __SPISE2P_H__
|
||||
|
||||
/* Physical EEPROM layout shared with the linker and SETGUI. */
|
||||
#include "eeprom_config.h"
|
||||
#include "include/balsam167_eeprom_layout.h"
|
||||
|
||||
// ¨ìêîñòü ïàìàòè â áàéòàõ
|
||||
#define SEEPROM_LEN 0x10000
|
||||
/* Preserve compact 16-bit arithmetic for the original 32-KiB build.
|
||||
* Only the large part needs 32-bit word addresses and transfer lengths. */
|
||||
#if EEPROM_M95M02
|
||||
typedef unsigned long SE2P_SIZE;
|
||||
#else
|
||||
typedef unsigned int SE2P_SIZE;
|
||||
#endif
|
||||
#define SEEPROM_LEN BALSAM167_EEPROM_BYTES
|
||||
|
||||
#define NULL 0
|
||||
|
||||
@@ -58,8 +69,10 @@ typedef struct {
|
||||
|
||||
/* Object declaration */
|
||||
typedef struct {
|
||||
SE2P_DATA *msgPtr;
|
||||
unsigned int csr; /* control/status register */
|
||||
/* Main loop publishes the descriptor before setting csr; Timer2 consumes it.
|
||||
* Both accesses are volatile so optimization cannot publish the request first. */
|
||||
SE2P_DATA * volatile msgPtr;
|
||||
volatile unsigned int csr; /* control/status register */
|
||||
void (*init)(void *);
|
||||
void (*tick)(void *);
|
||||
void (*csset)(void);
|
||||
@@ -85,12 +98,12 @@ void spiSe2pWrite(SPISE2P_DRV *se2p, SE2P_DATA *data);
|
||||
void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *data);
|
||||
|
||||
#if(SPISE2P_DATA_WIDTH==SIXTEEN_BIT)
|
||||
#define PROM_LEN 0x8000
|
||||
#define PAGE_LEN 0x20
|
||||
#define PROM_LEN BALSAM167_EEPROM_WORDS
|
||||
#define PAGE_LEN (BALSAM167_EEPROM_PAGE_BYTES / 2)
|
||||
#define WORD_LEN 2
|
||||
#else
|
||||
#define PROM_LEN 0x4000
|
||||
#define PAGE_LEN 0x40
|
||||
#define PROM_LEN BALSAM167_EEPROM_BYTES
|
||||
#define PAGE_LEN BALSAM167_EEPROM_PAGE_BYTES
|
||||
#define WORD_LEN 1
|
||||
#endif
|
||||
|
||||
@@ -105,7 +118,7 @@ void InitSeeprom(void);
|
||||
** adres = 0..0x4000, åñëè äëèíà ñëîâà 16 áèò **
|
||||
** buf - óêàçàòåëü íà ïàìàòü, îòêóäà ïèñàòü. **
|
||||
** size - äëèíà áëîêà â áàéòàõ. Ïî-ëþáîìó â áàéòàõ! */
|
||||
void Seeprom_write(unsigned int adres, unsigned int buf[], unsigned int size);
|
||||
void Seeprom_write(SE2P_SIZE adres, unsigned int buf[], SE2P_SIZE size);
|
||||
|
||||
/* ×òåíèå áëîêà èç SEEPROM. Ïàðàìåòðû òàêîâû: **
|
||||
** adres - àäðåñ â åïðîìêå, îòêóäà ÷èòàòü. **
|
||||
@@ -113,7 +126,7 @@ void Seeprom_write(unsigned int adres, unsigned int buf[], unsigned int size);
|
||||
** adres = 0..0x4000, åñëè äëèíà ñëîâà 16 áèò **
|
||||
** buf - óêàçàòåëü íà ïàìàòü, êóäà ÷èòàòü. **
|
||||
** size - äëèíà áëîêà â áàéòàõ. Ïî-ëþáîìó â áàéòàõ! */
|
||||
void Seeprom_read(unsigned int adres, unsigned int buf[], unsigned int size);
|
||||
void Seeprom_read(SE2P_SIZE adres, unsigned int buf[], SE2P_SIZE size);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -398,7 +398,16 @@ void extendbios(RS_DATA *rs_arr)
|
||||
switch ( code )
|
||||
{
|
||||
// Ïðîøèâàåì EPROM Èç RAM
|
||||
case 4: Seeprom_write(Address1,(unsigned int*)Address2,Length);
|
||||
#if EEPROM_M95M02
|
||||
/* 0x44 is intentionally rejected by old firmware. Conversely this build
|
||||
* rejects legacy code 4, preventing writes with the wrong GUI profile. */
|
||||
case 0x44:
|
||||
#else
|
||||
case 4:
|
||||
#endif
|
||||
if (!Length || Address1 >= BALSAM167_EEPROM_FIRMWARE_BYTES/2UL ||
|
||||
Length > BALSAM167_EEPROM_FIRMWARE_BYTES-Address1*2UL) return;
|
||||
Seeprom_write(Address1,(unsigned int*)Address2,Length);
|
||||
break;
|
||||
// ×èòàåì èç EPROM â RAM
|
||||
case 5: Seeprom_read(Address1,(unsigned int*)Address2,Length);
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#include "message.h"
|
||||
#include "peripher.h"
|
||||
#include "log_to_mem.h"
|
||||
#include "DAC.h"
|
||||
#include "ump_can_protocol.h"
|
||||
#include "gas167.h"
|
||||
|
||||
|
||||
// Prototype statements for functions found within this file.
|
||||
@@ -234,11 +236,18 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
|
||||
Data[1] = (loword>>16) & 0xffff;
|
||||
Data[2] = (loword ) & 0xffff;
|
||||
|
||||
if(bit[0]) if(adr < ANSWER_LEN) modbus[adr] = Data[0]; adr++;
|
||||
if(bit[1]) if(adr < ANSWER_LEN) modbus[adr] = Data[1]; adr++;
|
||||
if(bit[2]) if(adr < ANSWER_LEN) modbus[adr] = Data[2];
|
||||
if(bit[0]) if(adr < ANSWER_LEN &&
|
||||
!(Desk == dsk_LOAD && (adr == 0x7CU || adr == 0x7DU))) modbus[adr] = Data[0]; adr++;
|
||||
if(bit[1]) if(adr < ANSWER_LEN &&
|
||||
!(Desk == dsk_LOAD && (adr == 0x7CU || adr == 0x7DU))) modbus[adr] = Data[1]; adr++;
|
||||
if(bit[2]) if(adr < ANSWER_LEN &&
|
||||
!(Desk == dsk_LOAD && (adr == 0x7CU || adr == 0x7DU))) modbus[adr] = Data[2];
|
||||
|
||||
/* Ôèêñèðóåì ïðèìåí¸ííóþ êîìàíäó äî âûõîäà èç îáðàáîò÷èêà 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)
|
||||
Load_voltage_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);
|
||||
ump_log_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);
|
||||
led2_toggle();
|
||||
}
|
||||
@@ -316,7 +325,13 @@ void UMP_CAN_service(void)
|
||||
saved = __disable_interrupts();
|
||||
tag = ump_can_tag; address = ump_can_address; value = ump_can_value;
|
||||
ump_can_pending = 0;
|
||||
ump_can_length = ump_can_prepare(tag & 0xFF, address, value, ump_can_reply, &error);
|
||||
if (address >= 0x1300U && address < 0x1308U)
|
||||
ump_can_length = Load_protection_prepare(tag & 0xFF, address, value, ump_can_reply, &error);
|
||||
#if EEPROM_M95M02
|
||||
else if (gas167_contains(address))
|
||||
ump_can_length = gas167_prepare(tag & 0xFF, address, value, 1, ump_can_reply, &error);
|
||||
#endif
|
||||
else ump_can_length = ump_can_prepare(tag & 0xFF, address, value, ump_can_reply, &error);
|
||||
ump_can_reply_tag = (tag & 0xFF00) | error;
|
||||
ump_can_index = 0;
|
||||
__restore_interrupts(saved);
|
||||
|
||||
63
Source/Internal/gas167.c
Normal file
63
Source/Internal/gas167.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "gas167.h"
|
||||
#if EEPROM_M95M02
|
||||
#include "package.h"
|
||||
|
||||
extern int modbus[];
|
||||
extern int Desk;
|
||||
extern void ump_log_rs(void);
|
||||
|
||||
static const uint16_t gas167_info[GAS167_INFO_WORDS] = {
|
||||
0x4741U, 0x5331U, GAS167_PROFILE_VERSION, 167U,
|
||||
GAS167_REG_BASE, GAS167_REG_COUNT, GAS167_CAPABILITIES, 1U
|
||||
};
|
||||
|
||||
int gas167_contains(uint16_t address)
|
||||
{
|
||||
return (uint16_t)(address - GAS167_REG_BASE) < GAS167_REG_COUNT ||
|
||||
(uint16_t)(address - GAS167_INFO_BASE) < GAS167_INFO_WORDS;
|
||||
}
|
||||
|
||||
static unsigned gas167_write(uint16_t offset, uint16_t value)
|
||||
{
|
||||
/* Match the existing native Modbus write policy. These status words
|
||||
* cannot be overwritten and an invalid timeout cannot bypass protection. */
|
||||
if (Desk == dsk_LOAD && (offset == 0x7CU || offset == 0x7DU)) return 2;
|
||||
if (Desk == dsk_LOAD && offset == 0x52U &&
|
||||
(value == 0U || value > 60000U)) return 3;
|
||||
/* C28x int is one register word; reads always expose the raw uint16_t. */
|
||||
modbus[offset] = (int)value;
|
||||
if (offset == 127U) ump_log_rs();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned gas167_prepare(unsigned function, uint16_t address, uint16_t value,
|
||||
int can, uint16_t *reply, unsigned *error)
|
||||
{
|
||||
uint16_t offset;
|
||||
unsigned i, available;
|
||||
int info;
|
||||
if (!reply || !error) return 0;
|
||||
*error = 0;
|
||||
info = (uint16_t)(address - GAS167_INFO_BASE) < GAS167_INFO_WORDS;
|
||||
offset = (uint16_t)(address - (info ? GAS167_INFO_BASE : GAS167_REG_BASE));
|
||||
available = info ? GAS167_INFO_WORDS : GAS167_REG_COUNT;
|
||||
if (function != 3U && function != 6U) *error = 1;
|
||||
else if (offset >= available) *error = 2;
|
||||
else if (function == 6U) {
|
||||
*error = info ? 2U : gas167_write(offset, value);
|
||||
} else if (!value || value > GAS167_MAX_WORDS || (can && (value & 1U))) {
|
||||
*error = 3;
|
||||
} else if (value > available - offset) {
|
||||
*error = 2;
|
||||
} else {
|
||||
/* Validate the entire block before reading. A block cannot cross a
|
||||
* region boundary, wrap at 0xFFFF, or leak the hidden parameter word. */
|
||||
for (i = 0; i < value; ++i)
|
||||
reply[i] = info ? gas167_info[offset+i] : (uint16_t)modbus[offset+i];
|
||||
return value;
|
||||
}
|
||||
reply[0] = address;
|
||||
reply[1] = value;
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
@@ -31,17 +31,15 @@ void clear_mem()
|
||||
for (i=Log.Start; i<Log.Finis; i++)
|
||||
*(volatile int *)i = 0;
|
||||
}
|
||||
/* Два банка используют уже выделенную внешнюю RAM .logg (64000 слов).
|
||||
* Активный банк кольцевой. Через 1000 мс после команды отключения он
|
||||
* становится архивом, а запись продолжается во втором банке. Переключение
|
||||
* занимает постоянное время: копирования 30 тысяч слов под запретом IRQ нет.
|
||||
* Архив переживает разрыв RS-связи, но НЕ исчезновение питания платы. */
|
||||
/* Two RAM banks: freeze after 10% of bank capacity is recorded after stop. */
|
||||
static volatile unsigned int ump_state, ump_count, ump_cursor, ump_next;
|
||||
static volatile unsigned int ump_period = 20, ump_divider;
|
||||
static volatile unsigned long ump_time, ump_sequence;
|
||||
static unsigned int ump_bank, ump_archive_bank = 1;
|
||||
static unsigned int ump_archive_count, ump_archive_next, ump_generation;
|
||||
static unsigned int ump_source, ump_post, ump_post_dropped;
|
||||
static unsigned int ump_source, ump_post;
|
||||
#define UMP_POST_POINTS (UMP_LOG_CAPACITY / 10U)
|
||||
static void ump_freeze(void);
|
||||
static unsigned int ump_can_header, ump_can_data[3], ump_can_count;
|
||||
/* Latest PM67 sums: register 306 (index 305), register 9 (index 8). */
|
||||
static unsigned int ump_pm67_voltage[2];
|
||||
@@ -62,7 +60,7 @@ void ump_log_init(void)
|
||||
ump_time = 0; ump_sequence = 0;
|
||||
ump_bank = 0; ump_archive_bank = 1;
|
||||
ump_archive_count = 0; ump_archive_next = 0; ump_generation = 0;
|
||||
ump_source = 0; ump_post = 0; ump_post_dropped = 0;
|
||||
ump_source = 0; ump_post = 0;
|
||||
ump_can_header = 0; ump_can_count = 0;
|
||||
for (i = 0; i < 3; i++) ump_can_data[i] = 0;
|
||||
for (i = 0; i < 2; i++) ump_pm67_voltage[i] = 0;
|
||||
@@ -95,32 +93,30 @@ static unsigned int ump_outputs(void)
|
||||
static void ump_capture(unsigned int reason)
|
||||
{
|
||||
volatile unsigned int *p;
|
||||
unsigned int i, commands;
|
||||
unsigned int i, commands, inputs, outputs;
|
||||
if (ump_state != 1 || Desk != dsk_LOAD || !READY) return;
|
||||
if (no_write || never_write) { ump_state = 3; return; }
|
||||
commands = Commands;
|
||||
/* Отключение: фронт cUMPreset (бит 6) либо спад cUMPstart (бит 7).
|
||||
* Повторные команды не сдвигают конец уже начатого постинтервала. */
|
||||
if (!ump_post && (((commands & 0x40) && !(ump_prev_commands & 0x40)) ||
|
||||
(!(commands & 0x80) && (ump_prev_commands & 0x80)))) {
|
||||
/* Половину банка резервируем под постинтервал. Даже при периоде
|
||||
* 1 мс или шквале CAN событие отключения не вытесняется кольцом. */
|
||||
if (ump_count >= UMP_LOG_CAPACITY/2) ump_count = UMP_LOG_CAPACITY/2-1;
|
||||
ump_post_dropped = 0;
|
||||
ump_post = 1000;
|
||||
inputs = ump_inputs(); outputs = ump_outputs();
|
||||
/* Freeze only an actual running-to-stopped output transition.
|
||||
* STOP is set before RES_OUT_2 is cleared in main; an interrupt can
|
||||
* observe these writes separately, so require its level, not its edge.
|
||||
* Repeated reset/STOP pulses while already stopped leave the archive. */
|
||||
if (!ump_post && (ump_prev_outputs & 4U) && !(outputs & 4U) &&
|
||||
(outputs & 2U)) {
|
||||
/* Keep 90% including the trigger; reserve 10% for later records. */
|
||||
if (ump_count >= UMP_LOG_CAPACITY - UMP_POST_POINTS)
|
||||
ump_count = UMP_LOG_CAPACITY - UMP_POST_POINTS - 1;
|
||||
ump_post = UMP_POST_POINTS;
|
||||
reason |= 0x100;
|
||||
}
|
||||
/* Последнее место оставляем для снимка конца постинтервала. При
|
||||
* переполнении честно отмечаем усечение битом 0x200 в конечной записи. */
|
||||
if (ump_post && ump_count >= UMP_LOG_CAPACITY-1) {
|
||||
ump_post_dropped = 1;
|
||||
return;
|
||||
}
|
||||
if (reason == 5 && ump_post_dropped) reason |= 0x200;
|
||||
ump_prev_commands = commands; ump_prev_inputs = inputs; ump_prev_outputs = outputs;
|
||||
/* Every stored point counts, including CAN and I/O, except the trigger. */
|
||||
if (ump_post && !(reason & 0x100) && --ump_post == 0) reason = 5;
|
||||
p = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS;
|
||||
p[0] = (unsigned int)ump_time; p[1] = (unsigned int)(ump_time >> 16);
|
||||
p[2] = reason; p[3] = commands;
|
||||
p[4] = ump_inputs(); p[5] = ump_outputs();
|
||||
p[4] = inputs; p[5] = outputs;
|
||||
p[6] = (unsigned int)IMPowse; p[7] = (unsigned int)WAKEpowse;
|
||||
p[8] = modbus[0x7B]; p[9] = modbus[0x1C];
|
||||
for (i = 0; i < 4; i++) { p[10+i] = sens_data[i]; p[14+i] = modbus[i]; }
|
||||
@@ -136,11 +132,11 @@ static void ump_capture(unsigned int reason)
|
||||
p[33] = ump_dac_go10; p[34] = ump_dac_stop10; p[35] = ump_dac_position;
|
||||
for (i = 0; i < 4; i++) p[36+i] = ADC_table[i];
|
||||
p[40] = ump_pm67_voltage[0]; p[41] = ump_pm67_voltage[1];
|
||||
ump_prev_commands = commands; ump_prev_inputs = p[4]; ump_prev_outputs = p[5];
|
||||
ump_next++;
|
||||
if (ump_next == UMP_LOG_CAPACITY) ump_next = 0;
|
||||
if (ump_count < UMP_LOG_CAPACITY) ump_count++;
|
||||
ump_sequence++;
|
||||
if (reason == 5) ump_freeze();
|
||||
}
|
||||
|
||||
/* Çàâåðø¸ííûé áàíê áîëüøå íå èçìåíÿåòñÿ äî ñëåäóþùåãî îòêëþ÷åíèÿ.
|
||||
@@ -160,10 +156,6 @@ void ump_log_tick(void)
|
||||
if (ump_state == 1) {
|
||||
ump_time++;
|
||||
if (++ump_divider >= ump_period) { ump_divider = 0; ump_capture(1); }
|
||||
if (ump_post && --ump_post == 0) {
|
||||
ump_capture(5);
|
||||
ump_freeze();
|
||||
}
|
||||
}
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
@@ -224,6 +216,7 @@ int ump_log_write(unsigned int address, unsigned int value)
|
||||
ump_count = 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0;
|
||||
ump_source = 0;
|
||||
ump_prev_commands = Commands;
|
||||
ump_prev_inputs = ump_inputs(); ump_prev_outputs = ump_outputs();
|
||||
no_write = 0; never_write = 0;
|
||||
ump_state = 1;
|
||||
ump_capture(1);
|
||||
@@ -274,7 +267,11 @@ unsigned int ump_log_read(unsigned int address)
|
||||
case UMP_LOG_BASE+11: return (unsigned int)READY_FREQ;
|
||||
case UMP_LOG_BASE+12: return ump_generation;
|
||||
case UMP_LOG_BASE+13: return ump_archive_count;
|
||||
case UMP_LOG_BASE+14: return ump_post;
|
||||
/* Preserve the legacy millisecond status field as an upper estimate.
|
||||
* Additional event records may finish the post interval sooner. */
|
||||
case UMP_LOG_BASE+14:
|
||||
first = (unsigned long)ump_post * ump_period;
|
||||
return first > 65535UL ? 65535U : (unsigned int)first;
|
||||
case UMP_LOG_BASE+15: return ump_state;
|
||||
}
|
||||
if (address >= UMP_LOG_DATA && address < UMP_LOG_DATA+120 && (ump_source || ump_state != 1)) {
|
||||
|
||||
@@ -39,8 +39,6 @@ void main()
|
||||
{
|
||||
int i,j,mask;
|
||||
static unsigned int cancount[2], cancell[2], rscount;
|
||||
static int preCstart=1,preCstop=1;
|
||||
int umpstart,umpstop;
|
||||
RS_DATA * rs;
|
||||
int presbyt=0;
|
||||
|
||||
@@ -83,6 +81,7 @@ void main()
|
||||
|
||||
clear_mem();
|
||||
ump_log_init();
|
||||
Load_control_init(); /* Explicit initialization before IRQ. */
|
||||
set_cntrl_addr(Mode,16);
|
||||
timer_Init();
|
||||
EnableInterrupts();
|
||||
@@ -178,27 +177,8 @@ void main()
|
||||
presbyt = bTermoCal;
|
||||
}
|
||||
|
||||
if(Desk==dsk_LOAD)
|
||||
{
|
||||
umpstart = cUMPstart;
|
||||
umpstop = cUMPreset;
|
||||
|
||||
if(umpstart & !preCstart)
|
||||
{
|
||||
set_START_DPTB(); set_RES_OUT_2();
|
||||
IMPowse = READY_FREQ;
|
||||
}
|
||||
preCstart = umpstart;
|
||||
|
||||
if(umpstop & !preCstop)
|
||||
{
|
||||
set_STOP_DPTB(); clear_RES_OUT_2();
|
||||
IMPowse = READY_FREQ;
|
||||
}
|
||||
preCstop = umpstop;
|
||||
|
||||
if(!IMPowse) { clear_START_DPTB(); clear_STOP_DPTB(); }
|
||||
}
|
||||
/* Timer1 owns START/STOP/permission and the DAC ramp together.
|
||||
* Main must not re-enable the output during a protected reload. */
|
||||
|
||||
/* Ñíèìîê ïîñëå îáíîâëåíèÿ âõîäîâ è ôîðìèðîâàíèÿ ïóñêîâûõ âûõîäîâ. */
|
||||
ump_log_io();
|
||||
|
||||
@@ -417,7 +417,7 @@ void Init_packMask()
|
||||
if(Desk==dsk_LOAD)
|
||||
{ Maska[m_SLOW][7]|= 0x0030; // Êàëèáðîâêà ÖÀÏ
|
||||
Maska[m_SLOW][5]|= 0x0003; // Íà÷àëî è êîíåö çàðàäà
|
||||
Maska[m_FAST][7]|= 0xE000; // Дублировать команды
|
||||
Maska[m_FAST][7]|= 0xF000; /* Protection status 0x7C + attempts 0x7D. */ // Äóáëèðîâàòü êîìàíäû
|
||||
Maska[m_FAST][1]|= 0x3000; // Óïðàâëàþùèé òîê ÑÈÔÓ
|
||||
} }
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "eeprom_config.h"
|
||||
#include "include/balsam167_eeprom_block.h"
|
||||
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
||||
#include "package.h"
|
||||
#include "RS485.h"
|
||||
@@ -18,7 +20,13 @@
|
||||
|
||||
#include "caliber.h"
|
||||
#include "log_to_mem.h"
|
||||
#include "DAC.h"
|
||||
#include "ump_tms28335.h"
|
||||
#include "gas167.h"
|
||||
#include "include/balsam167_eeprom_layout.h"
|
||||
#if (ANSWER_LEN + 1) != BALSAM167_EEPROM_PARAM_WORDS
|
||||
#error EEPROM_parameter_reservation_must_match_ANSWER_LEN
|
||||
#endif
|
||||
|
||||
int modbus[ANSWER_LEN+1];
|
||||
unsigned int param[ANSWER_LEN+1];
|
||||
@@ -126,6 +134,7 @@ void Default_params()
|
||||
|
||||
// Ïðèøëî âðåìà!
|
||||
DAC_go = 6; // íà÷àëî çàðàäà
|
||||
LOAD_CAN_TIMEOUT = 2000; /* ms without fresh ZPT: freeze ramp. */
|
||||
DAC_stop= 16; // êîíåö çàðàäà
|
||||
|
||||
}
|
||||
@@ -141,7 +150,7 @@ void Load_params()
|
||||
{
|
||||
unsigned int i,crc;
|
||||
|
||||
Seeprom_read(0x3FFF-(ANSWER_LEN+1), param, (ANSWER_LEN+1)*2);
|
||||
Seeprom_read(BALSAM167_EEPROM_PARAMS_START_WORD, param, (ANSWER_LEN+1)*2);
|
||||
crc = get_crc16(param,ANSWER_LEN);
|
||||
if( (crc==param[ANSWER_LEN]) &&
|
||||
(crc !=0xFFFF) &&
|
||||
@@ -174,7 +183,7 @@ void Save_params()
|
||||
if(dif)
|
||||
{
|
||||
param[ANSWER_LEN] = get_crc16(param,ANSWER_LEN);
|
||||
Seeprom_write(0x3FFF-(ANSWER_LEN+1),param,(ANSWER_LEN+1)*2);
|
||||
Seeprom_write(BALSAM167_EEPROM_PARAMS_START_WORD,param,(ANSWER_LEN+1)*2);
|
||||
} }
|
||||
|
||||
/***************************************************************/
|
||||
@@ -206,9 +215,39 @@ static int receive_ump(RS_DATA *rs_arr)
|
||||
address = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3];
|
||||
if (address < UMP_BASE) return 0;
|
||||
value = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||||
/* SPI driver advances in Timer2 ISR: NEVER mask interrupts here.
|
||||
* Reuse the existing snapshot buffer; the main loop owns this transaction.
|
||||
* The shared validator rejects writes, wraparound and out-of-device reads. */
|
||||
if (address >= 0x1300U && address < 0x1308U) {
|
||||
count = Load_protection_prepare(rs_arr->RS_Header[1], address, value, words, &error);
|
||||
} else if (address >= BALSAM167_EEPROM_RTU_BASE) {
|
||||
error = 2;
|
||||
#if EEPROM_M95M02
|
||||
/* Exception 3 prevents old AT-profile clients from falling back to
|
||||
* legacy PEEK after a profile mismatch. No SPI transaction is issued. */
|
||||
if (!(value & BALSAM167_EEPROM_M95_MARKER)) error = 3;
|
||||
#endif
|
||||
count = 0;
|
||||
if (balsam167_eeprom_block_valid(rs_arr->RS_Header[1], address, value)) {
|
||||
#if EEPROM_M95M02
|
||||
count = value & 255U;
|
||||
Seeprom_read(balsam167_eeprom_block_word(address, value), words, count * 2);
|
||||
#else
|
||||
count = value;
|
||||
Seeprom_read(address - BALSAM167_EEPROM_RTU_BASE, words, count * 2);
|
||||
#endif
|
||||
error = 0;
|
||||
}
|
||||
} else {
|
||||
saved = __disable_interrupts();
|
||||
#if EEPROM_M95M02
|
||||
if (gas167_contains(address))
|
||||
count = gas167_prepare(rs_arr->RS_Header[1], address, value, 0, words, &error);
|
||||
else
|
||||
#endif
|
||||
count = ump_tms28335_capture(rs_arr->RS_Header[1], address, value, words, &error);
|
||||
__restore_interrupts(saved);
|
||||
}
|
||||
length = ump_rtu_encode(CNTRL_ADDR, rs_arr->RS_Header[1], error,
|
||||
words, count, rs_arr->buffer, MAX_SEND_LENGTH);
|
||||
if (length) {
|
||||
@@ -289,6 +328,13 @@ void ReceiveCommandModbus6(RS_DATA *rs_arr)
|
||||
// ïîëó÷èëè ñëîâî äàííûõ
|
||||
Data_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5];
|
||||
|
||||
if (Desk == dsk_LOAD && (Address_MB == 0x7CU || Address_MB == 0x7DU)) {
|
||||
modbus_exception(rs_arr, CMD_MODBUS_6, 2); return;
|
||||
}
|
||||
if (Desk == dsk_LOAD && Address_MB == 0x52U &&
|
||||
(Data_MB == 0U || Data_MB > 60000U)) {
|
||||
modbus_exception(rs_arr, CMD_MODBUS_6, 3); return;
|
||||
}
|
||||
if (Address_MB < ANSWER_LEN) {
|
||||
Modbus[Address_MB].all = Data_MB;
|
||||
if (Address_MB == 127) ump_log_rs();
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/* Build the canonical sources directly; do not copy their implementations. */
|
||||
#include "../firmware-info/src/firmware_info_static.c"
|
||||
/* Bind only this PM35 application's identity. The shared transport still owns
|
||||
* range checks, read-only access, CRC and CAN fragment packing. */
|
||||
#define UMP_FIRMWARE_INFO_READ firmware_info_static_read
|
||||
#include "src/ump_protocol.c"
|
||||
#include "ports/tms320f28335/ump_tms28335.c"
|
||||
|
||||
@@ -19,12 +19,18 @@ int ccc=0;
|
||||
/******* SPI bus Serial EEPROM driver Initialization routine ********/
|
||||
/********************************************************************/
|
||||
|
||||
void Seeprom_write( unsigned int adres,
|
||||
void Seeprom_write( SE2P_SIZE adres,
|
||||
unsigned int buf[],
|
||||
unsigned int size)
|
||||
SE2P_SIZE size)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
#if EEPROM_M95M02
|
||||
/* Bound physical accesses before byte-to-word rounding. Legacy 32-KiB
|
||||
* callers retain their compact driver; EXTEND is checked independently. */
|
||||
if (adres >= PROM_LEN || !size || size > (PROM_LEN-adres)*2) return;
|
||||
#endif
|
||||
|
||||
CpuTimer2.InterruptCount=0;
|
||||
CpuTimer2Regs.TCR.all = 0x4020; // Use write-only instruction to set TSS bit = 0
|
||||
|
||||
@@ -50,12 +56,18 @@ void Seeprom_write( unsigned int adres,
|
||||
CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1
|
||||
}
|
||||
|
||||
void Seeprom_read( unsigned int adres,
|
||||
void Seeprom_read( SE2P_SIZE adres,
|
||||
unsigned int buf[],
|
||||
unsigned int size)
|
||||
SE2P_SIZE size)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
#if EEPROM_M95M02
|
||||
/* Bound physical accesses before byte-to-word rounding. Legacy 32-KiB
|
||||
* callers retain their compact driver; EXTEND is checked independently. */
|
||||
if (adres >= PROM_LEN || !size || size > (PROM_LEN-adres)*2) return;
|
||||
#endif
|
||||
|
||||
CpuTimer2.InterruptCount=0;
|
||||
CpuTimer2Regs.TCR.all = 0x4020; // Use write-only instruction to set TSS bit = 0
|
||||
|
||||
@@ -244,6 +256,15 @@ void SPISE2P_DRV_tick(SPISE2P_DRV *eeprom)
|
||||
case 5:
|
||||
/* Send Address */
|
||||
|
||||
#if EEPROM_M95M02
|
||||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||||
SpiaRegs.SPITXBUF=(unsigned int)(eeprom->msgPtr->se2pAddr >> 16) << 8;
|
||||
step=20;
|
||||
break;
|
||||
case 20:
|
||||
if (!SpiaRegs.SPISTS.bit.INT_FLAG) break;
|
||||
dummy=SpiaRegs.SPIRXBUF;
|
||||
#endif
|
||||
#if(SPISE2P_ADDR_WIDTH==SIXTEEN_BIT)
|
||||
SpiaRegs.SPICCR.all= SPISE2P_TFR16BIT;
|
||||
SpiaRegs.SPITXBUF=eeprom->msgPtr->se2pAddr;
|
||||
@@ -374,7 +395,16 @@ void SPISE2P_DRV_tick(SPISE2P_DRV *eeprom)
|
||||
case 15:
|
||||
/* Send Address */
|
||||
|
||||
#if(SPISE2P_ADDR_WIDTH==SIXTEEN_BIT)
|
||||
#if EEPROM_M95M02
|
||||
SpiaRegs.SPICCR.all=SPISE2P_TFR8BIT;
|
||||
SpiaRegs.SPITXBUF=(unsigned int)(eeprom->msgPtr->se2pAddr >> 16) << 8;
|
||||
step=21;
|
||||
break;
|
||||
case 21:
|
||||
if (!SpiaRegs.SPISTS.bit.INT_FLAG) break;
|
||||
dummy=SpiaRegs.SPIRXBUF;
|
||||
#endif
|
||||
#if(SPISE2P_ADDR_WIDTH==SIXTEEN_BIT)
|
||||
SpiaRegs.SPICCR.all= SPISE2P_TFR16BIT;
|
||||
SpiaRegs.SPITXBUF=eeprom->msgPtr->se2pAddr;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user