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:
2026-10-09 16:17:37 +03:00
parent c6c9128238
commit 5d9818291b
63 changed files with 2307 additions and 365 deletions
+48 -2
View File
@@ -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();