Teensy 4.0 / High Voltage Heater

BUT since ID33 is also a 3 byte message, shouldn't we also modify ID 33 to:
Code:
lin.order(0x33, lindata2, 3, lin2x);
If we do this, do we need to put a number into BYTE 3 as well?
Code:
 uint8_t lindata2[] = { 0x00, 0x08, ????? };  // checksum 0, counter 0, enable
ID33 is a really a 2 LIN data byte message.
It's a typo from their side. From the specs:

1723556636014.png

1723556709912.png


They probably better stop using the word 'byte'; we are talking 'registers' here with a certain bit length.
What does "with a byte length of 3 bytes" actually mean??

Look at the confusing ID17 description:

1723556928867.png

We are talking 2 registers here, each with a bit-length of 10 bits. And therefor we pack those 20 bits in 3 LIN data bytes.

Paul
 
I imported the above code and here was the response without 12V (along with HV ready):

responseID:17,Response Data:0x00 0x00 0x1B ,CRC:255
responseID:17,Response Data:0x00 0x00 0x1B ,CRC:255
responseID:17,Response Data:0x00 0x00 0x1B ,CRC:255

Once the 12V was applied to the heater (along with HV ready):

responseID:17,Response Data:0x00 0x00 0x00 ,CRC:255
responseID:17,Response Data:0x00 0x00 0x00 ,CRC:255
responseID:17,Response Data:0x00 0x00 0x00 ,CRC:255
I think CRC 255 means error?
 
I think CRC 255 means error?
Yes it does. When I change the ID17 back to 4 from3 it gives a 0 for CRC when power is applied, but still 0x00 for the temp.

Code:
responseID:17,Response Data:0x00 0x00 0x00 0x68 ,CRC:0
 
If I change ID7 to 2 bytes, I get:

Code:
responseID:17,Response Data:0x00 0x00 ,CRC:255
responseID:17,Response Data:0x00 0x00 ,CRC:255
responseID:17,Response Data:0x00 0x00 ,CRC:104 (power on)
 
If I change ID7 to 2 bytes, I get:

Code:
responseID:17,Response Data:0x00 0x00 ,CRC:255
responseID:17,Response Data:0x00 0x00 ,CRC:255
responseID:17,Response Data:0x00 0x00 ,CRC:104 (power on)
That CRC: 104 is correct with both data bytes being 0x00:
1723558819594.png
 
I'm a bit lost though - I wonder if we are doing something fundamentally wrong in the LIN communication to the heater, because what we see doesn't make sense.

Well, I do hope the supplier will come back with some sort of initialisation sequence or init code.

Paul
 
Thanks Paul. Me too!

The CRC gives an error all the time on 3 bytes, 0s all the time on 4 bytes and 104 on 2 bytes, BUT in no configuration, do I jump off of 0x00 for the data we need to change.

If 0x17 is 10+10 bits, it has to be 3 bytes, but I feel the issue is still in the initialization sequence of ID22 and ID33 right? I assume we would not get 0x00 if those were getting the heater to activate????
 
If 0x17 is 10+10 bits, it has to be 3 bytes, but I feel the issue is still in the initialization sequence of ID22 and ID33 right? I assume we would not get 0x00 if those were getting the heater to activate????
Agree, reading ID17 is not required for the heater to activate. I was hoping that only writing ID22 & ID33 would be enough to kick off the heater.

Paul
 
I wrote to them again and hope they respond with something helpful. In the meantime, is there any type of sniffing routine we could run again to see if there is some combination of bytes and bits to get some sign of life?
 
In the meantime, is there any type of sniffing routine we could run again to see if there is some combination of bytes and bits to get some sign of life?
Like a kind of brute-force attack? Hmm, too many possible input combinations to my taste. And how to verify the output?

What came to mind though is whether there is a requirement on how to apply the voltages timing-wise. Like 12V first to get the built-in MCU to boot & run and then apply the HighVoltage? Found nothing in the specs about this.

Paul
 
I think the HV has to be present first because as soon as I start the car, the HV contactors open up and the HV becomes available for the AC compressor, heater and DC/DC components. I think the next question is from the LDF on the timing and if any of this info matters:

Code:
Nodes {
    Master: VDDM, 5.000 ms, 1.000 ms;
    Slaves: HVCH;
}

Schedule_tables {
    Ecm_Lin1DiagRequestSchedule {
        MasterReq delay 15.000 ms;
    }
    Ecm_Lin1DiagResponseSchedule {
        SlaveResp delay 15.000 ms;
    }
    Ecm_Lin1LinScheduleSerNrTable {
        HvchEcm_Lin1PartNr10Fr04 delay 15.000 ms;
        HvchEcm_Lin1PartNr10Fr08 delay 10.000 ms;
        HvchEcm_Lin1SerNrFr01 delay 10.000 ms;
    }
 
Hi Paul. Well we have another response from China. A lot of information to share.


On the Checksum / Counter issue (as you suspected):

The controller does not care about the contents of HvCooltHeatrNadWhE2EChks and HvCoolt HeatrNadWhE2ECntr, so these two values can be left blank


Regarding 0x33 being listed as 3 bytes:

At present, the length of the 0x33 message is defined as 3, and only 2 LIN data bytes are actually sent. The controller will report ErrRespHVCH (LIN response error)

Regarding the initialization sequence:


The signal timing example when the heater is started is shown in the following figure, where ECM is Master and HVCH is the heater

Step 1: The heater continuously reports status information

Step 2: ECM is required to send enable, flow rate, and target water temperature (the heater will calculate the expected power based on these signals)

Step 3: ECM sends allowed power to the heater

Step 4: Compare the minimum power values of Step 2 and Step 3 heaters and report them to the signal HvHeatrPrCnsDes

Step 5: The heater operates according to the power indicated by the HvHeatrPrCnsDes signal

It should be noted that:

1. The Master must first send the allowed power, otherwise the heater will continue to report HvHeatrPrCnsDes=0 and cannot work

2. HvWtRHeatrWrTDes (target water temperature of heater) ≤ 85 ℃

3. CooltFlowInCmptmtCirc (heater water flow rate) should be greater than 10L/min as much as possible to avoid heater derating operation

1723683201320.png

If the above response still does not solve the problem, please use LIN bus tool to record the bus message of the entire process, which will facilitate our continued troubleshooting

From the LDF file the references to HvHeatrPwrCnsDes are below:


Code:
Signals {
HvHeatrPwrCns: 10, 0, HVCH, VDDM;
HvHeatrPwrCnsDes: 10, 0, HVCH, VDDM;
HvWtrHeatrPwrCnsAllwd: 8, 0, VDDM, HVCH;
}

Frames {
    HvchEcm_Lin1Fr02: 0x17, HVCH, 3 {
        HvHeatrPwrCns, 0;
        HvHeatrPwrCnsDes, 10;
  }
    EcmEcm_Lin1Fr03: 0x22, VDDM, 4 {
        CooltFlowInCmptmtCirc, 16;
        HvCooltHeatrEnad, 27;
        HvWtrHeatrPwrCnsAllwd, 0;
        HvWtrHeatrWtrTDes, 8;
    }
    EcmEcm_Lin1Fr05: 0x33, VDDM, 3 {
        HvCooltHeatrEnadWhE2EChks, 0;
        HvCooltHeatrEnadWhE2ECntr, 8;
        HvCooltHeatrEnadWhE2EHvchEnad, 12;
    }



Signal_representation {
Pwr3 : HvHeatrPwrCns, HvHeatrPwrCnsDes;
HvHeatrPwrLim : HvWtrHeatrPwrCnsAllwd;
 
Last edited:
Hi Jordan, that flowchart helped a lot to clearify.
In the flowchart below I noted the register IDs in red. I skip reading out status register ID27 for now.

1723908143773.png


So we have to write ID33 first , then ID22 and then finally ID22 again.

Below the code that does that. I moved writing ID33 & ID22 to setup().

C++:
#include "lin_bus.h"

LIN lin;

int lin_cs = 32;  // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23;
int lin_fault = 28;

uint8_t data[4];
uint8_t CRC = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault, INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);  // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  //Serial.print("Heater demo");

  lin.begin(&Serial3, 19200);
  delay(100);  // wait 100ms
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // write ID33 register
  uint8_t lindata0[] = { 0x00, 0x08 };  // chechksum 0, counter 0, HvCooltHeatrEnadWhE2EHvchEnad = 1
  lin.order(0x33, lindata0, 2, lin2x);
  delay(100);

  // write ID22 register, HvWtrHeatrPwrCnsAllwd = 0
  uint8_t lindata1[] = { 0x00, 0x78, 0xFF, 0xD0 };  // 0W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata1, 4, lin2x);
  delay(100);

  // write ID22 register again, HvWtrHeatrPwrCnsAllwd = 1000W
  uint8_t lindata2[] = { 0x19, 0x78, 0xFF, 0xD0 };  // 1000W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata2, 4, lin2x);
  delay(100);
}

void loop() {
  // read ID17 register
  CRC = lin.response(0x17, data, 3, lin2x);  // we need 10+10 bits according to spec, so request 3 bytes
  Serial.print("responseID:");
  Serial.print(0x17, HEX);
  Serial.print(",");
  Serial.print("Response Data:");
  for (int i = 0; i < 3; i++) {  // display received data
    Serial.printf("0x%.2X ", data[i]);
  }
  Serial.print(",");
  Serial.print("CRC:");
  Serial.println(CRC);  // -1 indicates crc error

  delay(2000);
}

I'm very curious now whether the heater will start!

Paul
 
Last edited:
Hi Paul. Thank you for reviewing the additional information and decoding it. Unfortunately, the new code did not produce heat, BUT I did take readings off of 0x27 and I thought it would be helpful to share.

Code:
responseID:27,Response Data:0x20 0x3E 0x00 0x83 0x3E 0x02 0x00 0xF5 ,CRC:0

Byte 0:
FALSE Heather Short Circuit
FALSE Heater Current exceed design range
FALSE Memory Failure
FALSE Repair Request
FALSE Permanent Error
4: Heater Operational - Heater Status Report

Byte 1:
64- Heater Outlet Water Temp

Byte 2:
0 - Heater actual current consumption

Byte 3:
13.1 - Heater low voltage measurement

Byte 4:
64 - Heater inlet water termp

Byte 5:
FALSE -  Water temp exceeds design range
TRUE - Communication fail!!!!!!!
FALSE - Failure occurs
FALSE- Warning reserved
FALSE - HV out of range
FALSE- LV out of range
FALSE - Heater Power Limit Protection Status
FALSE- Lin communication failure

Byte 6:
FALSE -  Hardware Protection
FALE- PCB overheating
FALSE - IGBT overheating
FALSE- Temp fault retention
FALSE - Inlet Water temp sensor failure
FALSE - Outlet Water temp sensor failure
FALSE- IGBT temp sensor failure
FALSE - PCB temp sensor failure

I am not sure what the communication fail message means since lin communication is confirmed as good, but that is the only feedback that is out of range when I start the heater up. I confirmed I am pulling 320V on the HV and confirmed the LIN cable is correctly connected up.

Thoughts on this error?

Also, I cannot get the CRC to read 0 unless I switch back to 8 bytes on 0x27 and 4 bytes on 0x17. I wonder if this programming thinks we are in 2.0 and not 2.1 or if there is a file I need to upload into the sketch to let it know this. Not sure if this has to do with the communication fail.

I also wonder if the key is going to be this issue with 0x33 and the 3 bytes vs 2 bytes issue.
 
Last edited:
Hi Jordan, the fight apparently isn't over yet...
I'm not sure what to think about the ID27 results.
But first I would like to focus on sending data to the heater to get it running.
Since he suggested this:
If the above response still does not solve the problem, please use LIN bus tool to record the bus message of the entire process, which will facilitate our continued troubleshooting
I pulled the logic analyzer out and captured the 3 frames to the heater, using this code:
C++:
// write ID33 register
  uint8_t lindata0[] = { 0x00, 0x08 };  // chechksum 0, counter 0, HvCooltHeatrEnadWhE2EHvchEnad = 1
  lin.order(0x33, lindata0, 2, lin2x);
  delay(100);

  // write ID22 register, HvWtrHeatrPwrCnsAllwd = 0
  uint8_t lindata1[] = { 0x00, 0x78, 0xFF, 0xD0 };  // 0W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata1, 4, lin2x);
  delay(100);

  // write ID22 register again, HvWtrHeatrPwrCnsAllwd = 1000W
  uint8_t lindata2[] = { 0x19, 0x78, 0xFF, 0xD0 };  // 1000W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata2, 4, lin2x);
  delay(100);
First message, to ID33:
ID33.png

Second message, to ID22:
ID22-1.png

Third message, to ID22 again:
ID22-2.png


All looks as intended. Since I'm measuring on the Teensy Serial3 TX pin, you may want to connect your oscilloscope on the actual LIN data line near the heater's LV connector and verify whether the data is actually making it up to that connector.

If that also looks good then the next step would be to share the captures and the code with the engineer for verification.

Paul.
 
Thanks Paul. I will do this and report back. Hopefully my oscilloscope settings from the last time will still be intact. I will make sure the baud rate is correct. Do you know if I can use my CSS CL1000: CAN Bus Logger & USB Interface along with SAVVYCAN to capture LIN signals?

Also, in the manual I saw this under the error sections and wondered if this also provided any clues:


17 Communication fail.
The LIN bus cannot receive correct bus data within 1600ms, the system LIN timeout fault is set to 1, the
controller stops sending heating power, and it recovers immediately after receiving valid LIN bus data.
If Lin communication has no bus activity for more than 4000ms, it will enter bus sleep and stop working.
Normal operation automatically resumes when bus activity resumes.
When Lin communication receives a data error, the controller generates a LinResponseError fault and reports
the fault unconditionally.
 
Last edited:
So I ran the below code:

Code:
#include "lin_bus.h"

LIN lin;

int lin_cs = 32;  // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23;
int lin_fault = 28;

uint8_t data[4];
uint8_t CRC = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault, INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);  // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  //Serial.print("Heater demo");

  lin.begin(&Serial3, 19200);
  delay(100);  // wait 100ms
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {

  // write ID33 register
  uint8_t lindata0[] = { 0x00, 0x08 };  // chechksum 0, counter 0, HvCooltHeatrEnadWhE2EHvchEnad = 1
  lin.order(0x33, lindata0, 2, lin2x);
  delay(100);

  // write ID22 register, HvWtrHeatrPwrCnsAllwd = 0
  uint8_t lindata1[] = { 0x00, 0x78, 0xFF, 0xD0 };  // 0W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata1, 4, lin2x);
  delay(100);

  // write ID22 register again, HvWtrHeatrPwrCnsAllwd = 1000W
  uint8_t lindata2[] = { 0x19, 0x78, 0xFF, 0xD0 };  // 1000W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata2, 4, lin2x);
  delay(100);
}

I moved the lin.order code to the loop. Otherwise, I was getting nothing. I am getting strange results:

0x33 never shows up
0x22 never shows up BUT when I isolate to just the first 0x22 command, I get 0x21 with your power at on the oscilloscope and with the second command I get 0x20 or 0x00 depending on what value is in the power slot (0x19 vs oxB4 for example).

I am using multiple teensy boards to make sure it is not a board issue and my oscilloscope is taking a reading at the lin out from the teensy.
 

Attachments

  • PXL_20240818_174823865.jpg
    PXL_20240818_174823865.jpg
    175.2 KB · Views: 21
  • PXL_20240818_174817075.jpg
    PXL_20240818_174817075.jpg
    208.3 KB · Views: 20
  • PXL_20240818_174650462.jpg
    PXL_20240818_174650462.jpg
    233.5 KB · Views: 20
  • PXL_20240818_174631523.jpg
    PXL_20240818_174631523.jpg
    222.1 KB · Views: 20
  • PXL_20240818_172918330.jpg
    PXL_20240818_172918330.jpg
    259.5 KB · Views: 21
Hmm, strange results.
Tomorrow, I will hookup my SK Pang LIN-Bus Breakout Board and check with the oscilloscope as well.
With respect to the use of the CSS CL1000: I don't think it's usable since it is a CAN bus logger only.

Paul
 
SO . . . I have HOT water.

I spent the afternoon checking and re-checking everything and questioning the whole setup and wiring. I went into the older code we were using and tried that to no avail. Then I looked at the coding for 0x33 and was reworking the binary calculations.

0x33
Byte0 0 8 HvCooltHeatrEnadWhE2EChks E2Echecksum 0x0-0xFF:0-255
Byte1 8 4 HvCooltHeatrEnadWhE2ECntr E2Ecounter 0x0-0xF:0-15
Byte1 12 1 HvCooltHeatrEnadWhE2EHvchEnad HVCHenable signal 0:BooleanFALSE 1:BooleanTRUE

So for byte 1, I needed 0000 and 1000 which converts to 8 as you calculated. For some reason, I thought to try this as a 7 bits instead of 8. Don't ask me why. So when I flipped it and entered 0010000 into the calculator, it gave me 10. I changed the enable to 0x10 and it started to heat!!!!!!! Dumb luck . . . but all of your reworking of the code worked and it got very hot. Also, the 0x17 feeback came out showing the requested heat jumping around:

Code:
responseID:17,Response Data:0x2B 0xA0 0x05   
 
responseID:17,Response Data:0x35 0xA0 0x05   
 
responseID:17,Response Data:0x3F 0xA0 0x05   
 
responseID:17,Response Data:0x4B 0xA0 0x05   
 
responseID:17,Response Data:0x56 0xA0 0x05   
 
responseID:17,Response Data:0x64 0xA0 0x05   
 
responseID:17,Response Data:0x75 0xA0 0x05   
 
responseID:17,Response Data:0x84 0xA0 0x05   
 
responseID:17,Response Data:0x96 0xA0 0x05   
 
responseID:17,Response Data:0xAC 0xA0 0x05   
 
responseID:17,Response Data:0xC0 0xA0 0x05   
 
responseID:17,Response Data:0xD9 0xA0 0x05   
 
responseID:17,Response Data:0xF1 0x00 0x00   
 
responseID:17,Response Data:0x00 0xA0 0x05   
 
responseID:17,Response Data:0x0E 0xA0 0x05   
 
responseID:17,Response Data:0x19 0xA0 0x05   
 
responseID:17,Response Data:0x21 0xA0 0x05


0x27 was also giving off good data:

Code:
responseID:27,Response Data:0x80 0x70 0x0D 0x81 0x6F 0x80 0x00

responseID:27,Response Data:0x80 0x70 0x10 0x82 0x6F 0x80 0x00

Here is the code I ended up using that worked, which is really all of your code, but with some of the older stuff about blinking and the static lin lines and such. I am getting a warning still on the 0x27 data print with the 7 and not sure why.

Code:
#include "lin_bus.h"

// Create an IntervalTimer object
IntervalTimer myTimer;

int ledState = LOW;               // ledState used to set the LED
unsigned long interval = 200000;  // interval at which to blinkLED to run every 0.2 seconds

LIN lin;

int lin_cs = 32;  // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23; // sk pang board builtin led
int lin_fault = 28;

uint8_t CRC = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault, INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);  // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  //Serial.print("Heater demo");

  lin.begin(&Serial3, 19200);
  delay(100);  // wait 100ms
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  myTimer.begin(blinkLED, interval);
}
  void loop() {
  // heater
  SendLin();
  delay(100); // wait 100ms
  //Serial.print(" Heater test\n");
}
void blinkLED() {
  ledState = !ledState;
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}
   static void SendLin()
{
  //static bool read = true;
   uint8_t data[4];
   delay(100); // wait 100ms

    // read ID27 register
   lin.response(0x27, data, 7, lin2x); //
   delay(10);

  // write ID33 register
  uint8_t lindata0[] = { 0x00, 0x10 };  // chechksum 0, counter 0, HvCooltHeatrEnadWhE2EHvchEnad = 1
  lin.order(0x33, lindata0, 2, lin2x);
  delay(10);

  // write ID22 register, HvWtrHeatrPwrCnsAllwd = 0
  uint8_t lindata1[] = { 0x00, 0x78, 0xFF, 0xD0 };  // 0W power, 80C target temp, max flow, enable
  lin.order(0x22, lindata1, 4, lin2x);
  delay(10);

  // write ID22 register again, HvWtrHeatrPwrCnsAllwd = 1000W
  uint8_t lindata2[] = { 0xB4, 0x78, 0xFF, 0xD0 };  // 7200w power, 80C target temp, max flow, enable
  lin.order(0x22, lindata2, 4, lin2x);
  delay(10);

  // read ID17 register
  lin.response(0x17, data, 3, lin2x);  // we need 10+10 bits according to spec, so request 3 bytes
  Serial.print("responseID:");
  Serial.print(0x17, HEX);
  Serial.print(",");
  Serial.print("Response Data:");
  for (int i = 0; i < 3; i++) {  // display received data
  Serial.printf("0x%.2X ", data[i]);
  Serial.println("");
  }

  // read ID27 register
  lin.response(0x27, data, 7, lin2x);  //
  Serial.print("responseID:");
  Serial.print(0x27, HEX);
  Serial.print(",");
  Serial.print("Response Data:");
  for (int i = 0; i < 7; i++) {  // display received data
  Serial.printf("0x%.2X ", data[i]);
  Serial.println("");

  }

  delay(500);
}


THANK YOU PAUL FOR HANGING IN THERE WITH ME FOR THE PAST 6 MONTHS!!!!!!

PXL_20240818_223630834.jpg
 
Yeah, finally!
Who would have imagined that by shifting the enable bit 1 position to the left makes the whole thing work... well, you did apparently!

1724051572228.png

Sigh, so much for a correct datasheet. Are you going to feedback this to them or just be happy that it works?

I am getting a warning still on the 0x27 data print with the 7 and not sure why.
Oops, that's because I declared the data[] array too small. Please change line #47 from uint8_t data[4]; to uint8_t data[8];.

Well, this was a long and interesting journey! As usual, persistence pays off eventually.
Good luck with the rest of your project and feel free to share any updates. And ask questions of course!

Paul
 
Yeah, finally!
Who would have imagined that by shifting the enable bit 1 position to the left makes the whole thing work... well, you did apparently!

View attachment 35514
Sigh, so much for a correct datasheet. Are you going to feedback this to them or just be happy that it works?
The datasheet looks correct. Using the value of 8 was incorrect because the E2E counter is four bits - that means the enable bit is 1<<4, which is equivalent to 0x10.
 
Thanks guys. I cleaned up the code this morning so I can get some useful information on the serial monitor. Here are some readings from this morning over a period of 5 minutes:

Code:
RequestedPower:3520,
ActualPower:0
WaterTempIn:64,
WaterTempOut:64,
CurrentConsumption:0,
LowVoltageReading:13

RequestedPower:3520,
ActualPower:320
WaterTempIn:61,
WaterTempOut:61,
CurrentConsumption:1,
LowVoltageReading:13

RequestedPower:3680,
ActualPower:2180
WaterTempIn:120,
WaterTempOut:122,
CurrentConsumption:6,
LowVoltageReading:13

RequestedPower:1280,
ActualPower:1580
WaterTempIn:123,
WaterTempOut:124,
CurrentConsumption:4,
LowVoltageReading:13

RequestedPower:4000,
ActualPower:980
WaterTempIn:126,
WaterTempOut:127,
CurrentConsumption:3,
LowVoltageReading:12

If you are up for it, you can check my formulas in the below code to make sure the above readings are correct. I think I got it right based on the manual.

I also tried the code with just one entry for ID22 without the two step version and it seemed to work just fine, so I simplified things for anyone who stumbles across this post in the future.

Code:
#include "lin_bus.h"

// Create an IntervalTimer object
IntervalTimer myTimer;

int ledState = LOW;               // ledState used to set the LED
unsigned long interval = 200000;  // interval at which to blinkLED to run every 0.2 seconds

uint16_t requestedpower = 0;
uint16_t actualpower = 0;
uint16_t inwatertemp = 0;
uint16_t outwatertemp = 0;
uint16_t lowvoltage = 0;
uint16_t currentconsumption = 0;

LIN lin;

int lin_cs = 32;  // cs and serial port set for skpang LIN / FDCAN board
int led1 = 23; // sk pang board builtin led
int lin_fault = 28;

uint8_t CRC = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault, INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);  // enable MCP2004 LIN transceiver
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  //Serial.print("Heater demo");

  lin.begin(&Serial3, 19200);// Baud Rate for the SR02-2 Heater
  delay(100);  // wait 100ms
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  myTimer.begin(blinkLED, interval);
}
  void loop() {
  // heater
  SendLin();
  delay(100); // wait 100ms
  //Serial.print(" Heater test\n");
}
void blinkLED() {
  ledState = !ledState;
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}
   static void SendLin()
{
  //static bool read = true;
  uint8_t data[8];
  delay(100); // wait 100ms

  // read ID27 register
  lin.response(0x27, data, 7, lin2x); //
  delay(10);

  // write ID33 register
  uint8_t lindata0[] = { 0x00, 0x10 };  // chechksum 0, counter 0, HvCooltHeatrEnadWhE2EHvchEnad = 1 which is 0x10 Hex
  lin.order(0x33, lindata0, 2, lin2x);
  delay(10);

  // write ID22 register again, HvWtrHeatrPwrCnsAllwd = 6000W based on top voltage of 350V for my car
  uint8_t lindata2[] = { 0x96, 0x78, 0xFF, 0xD0 };  // 6000w power, 80C target temp, max flow, enable
  lin.order(0x22, lindata2, 4, lin2x);
  delay(10);

  // read ID17 register
  lin.response(0x17, data, 3, lin2x);  // we need 10+10 bits according to spec, so request 3 bytes
  {
  requestedpower = data[1] * 20;//(20w/bit) offset
  actualpower = data[0] * 20;//(20w/bit) offset
  Serial.print("RequestedPower:");
  Serial.print(requestedpower);
  Serial.println(",");
  Serial.print("ActualPower:");
  Serial.print(actualpower);
  Serial.println("");
  }

  // read ID27 register
  lin.response(0x27, data, 7, lin2x);  // we need 56 bits according to spec, so request 7 bytes
  inwatertemp = data[4];//(1℃/bit) offset
  outwatertemp = data[1];//(1℃/bit) offset
  lowvoltage = data[3] / 10;//(0.1V/bit) offset
  currentconsumption = data[2] / 4;//(0.25A/bit) offset
  Serial.print("WaterTempIn:");
  Serial.print(inwatertemp);
  Serial.println(",");
  Serial.print("WaterTempOut:");
  Serial.print(outwatertemp);
  Serial.println(",");
  Serial.print("CurrentConsumption:");
  Serial.print(currentconsumption);
  Serial.println(",");
  Serial.print("LowVoltageReading:");
  Serial.print(lowvoltage);
  Serial.println("");
  Serial.println("");
  delay(500);
  }
 
Back
Top