Teensy 4.0 / High Voltage Heater

Good morning, have a number of questions:
1. are you sure that the Webasto unit at hand is fully functional?
2. do you perhaps have an oscilloscope available so that you can measure on the actual LIN bus?
3. can it be that LINbus library has an issue with 2.1 LINbus frames? Hopefully someone on this forum has experience with LINbus V2.1 and can chime in.
4. do we only need function lin.response() to get data from a LIN device? I just opened a new thread on this question.

Paul
 
Good morning Paul.

I have 2 of the Webasto Heaters and have swapped them out to make sure one us not functioning.

I do not have an oscilloscope, but can always source one.

Here is a response I received on the OpenInverter Forum when I reported back on all of our work yesterday:

----------------------------------------------
Serial.print only prints 32 bits, data is 64. 0xFFFFFFFF = -1 which means no data received. This is why in my code there is the if statement so it only prints when data is received. If this was id 22 9600 baud then try id 24 at 19200.

lin.order(24, 0, 0, lin2x); requests data to be sent for id 24 ( 0,0 means no data sent only id). Unlike CAN, LIN does not transmit continuosly, so needs a data request.

I received my lin transceiver board today and have identified the receive id on my valeo heater matrix. So both tx and rx in the code are working thanks to the lin2x fix.

------------------------------------------------
 
Well, instead of Serial.println(lin.response(22, data, 8, lin2x), HEX);, we better use:
C++:
lin.response(22, data, 8, lin2x);
for (int i = 0; i < 8; i++) {
  Serial.println(data[i], HEX);
}

Paul
 
ok . . . so I made those changes:

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

uint8_t data[8];

void blinkLED() {
  ledState = !ledState;
 
  digitalWrite(LED_BUILTIN, ledState);
}
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);
 
  myTimer.begin(blinkLED, interval);

  LIN l(&Serial3, 9600);
  //LIN l(&Serial3, 19200); /// Change to this for 19200 /////
  lin = l;
 
}

void loop() {
  lin.order(22, 0, 0, lin2x);
  //lin.order(24, 0, 0, lin2x); /// Change to this for 19200 /////
  lin.response(22, data, 8, lin2x);
  //lin.response(24, data, 8, lin2x); /// Change to this for 19200 /////
  for (int i = 0; i < 8; i++) {
  Serial.println(data[i], HEX);
}
  digitalToggle(LED_BUILTIN);
  delay(1000);
}

and without the heater attached, I am getting a different response:

1707665611773.png

and on the plotter I am finally getting some action:

1707665646516.png

I will now go out and hook up the heater to this and see what happens.
 
hmmm . . so I am getting the same readings with or without the heater connected and powered up and same readings in both 9600 and 19200 modes.
 
Different readings here (without anything attached ofcourse):

1707679105146.png


Have to think about this... But not tonight I'm afraid - other obligations.

Paul
 
OK, continuing here:
"In order to receive data, data has to be requested. The second "if" sends a request header to ID 22 if in read mode, else it sends power command to ID 21. The code alternates between read and send every 100ms. The first "if" checks if data is received on ID 22 and if it has prints out the data. I am not sure on the timing of adding status read, whether it can be immediately after the request for id 22 is sent or has to be every 100ms after request/data is sent to id 21 and 22. Somewhere you also need to add lin.order(23, 0, 0, lin2x); to request data, lin.response(23, data, 8, lin2x) to read data and then decode each of the bytes".

OK, I think I understand. In your intial sketch, the software tries to read from the HVH using lin.response() and if it does not react (yet) sends a power-on message using lin.order(). And repeats this.

I'll come up with a basic sketch later tonight for you to try with your heater.

Paul
 
Hi Jordan, knowing what we learned in the other thread, here is a basic sketch that you could try with your HVH.
No fancy plotting yet, just raw data to the serial monitor:
C++:
#include "lin_bus.h"

uint16_t Power = 175;      // set to required power
uint8_t Temperature = 45;  // set to required temperature

LIN lin;

int lin_cs = 32;
uint8_t linTXdata[4] = { uint8_t(Power / 40), uint8_t(Temperature + 40), 0, 8 };
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);

  lin.begin(&Serial3, 19200);
}

void loop() {
  lin.order(35, linTXdata, 4, lin2x);     // set power, temp and heater ON
  delay(1);
  lin.response(24, linRXdata, 8, lin2x);  // read the data from the HVH
  for (int i = 0; i < 8; i++) {           // display the raw data
    Serial.println(linRXdata[i], HEX);
  }
  digitalToggle(LED_BUILTIN);
  delay(100);
}

The logic analyzer shows this:
DSView-240217-205832.png

The return data from the HVH should be appended after the ID: 0X18 byte.

Paul
 
Awesome. I will give it a try and report back!

And we do not need to send anything to ID 40 (23 for 9600) for this sketch?
 
And we do not need to send anything to ID 40 (23 for 9600) for this sketch?
If your unit is a 9600 baud version, then the code will look like this:
C++:
#include "lin_bus.h"

uint16_t Power = 175;      // set to required power
uint8_t Temperature = 45;  // set to required temperature

LIN lin;

int lin_cs = 32;
uint8_t linTXdata[4] = { uint8_t(Power / 40), uint8_t(Temperature + 40), 0, 8 };
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);

  lin.begin(&Serial3, 9600);  // lin.begin(&Serial3, 19200);
}

void loop() {
  lin.order(21, linTXdata, 4, lin2x);     // set power, temp and heater ON  // 9600: 21 instead of 35
  delay(1);
  lin.response(22, linRXdata, 8, lin2x);  // read the data from the HVH     // 9600: 22 instead of 24
  for (int i = 0; i < 8; i++) {           // display the raw data
    Serial.println(linRXdata[i], HEX);
  }
  digitalToggle(LED_BUILTIN);
  delay(100);
}
With reference to https://openinverter.org/wiki/Webasto_HVH50 . Nothing to send to 23 (40).

Paul
 
So, I tried both 9600 and 19200 versions with the heater on and off and only got the below response.

0
9C
16
0
20
8
0
0

I assume I need to see a 4 in the first byte position in order to know that the heater is actually on, right?
 
Somewhere you also need to add lin.order(23, 0, 0, lin2x); to request data, lin.response(23, data, 8, lin2x) to read data and then decode each of the bytes
That is definitely not correct. ID23 is a read status register, not a write register. So no reason to write to that status register. Perhaps a typo from his side.
1708207528062.png


Paul
 
That makes sense, but is there any info from this ID that would be useful? The manuals says:

■ Frame ID 35dez (LIN-master request: operation withpower and Ttarget temperature)

■ Frame ID 24dez (HVH-response frame 1: Power responseLIN-Signals

■ Frame ID 40dez (HVH-response frame 2: Status, diagnosis,warning and damage response LIN-signals )

LIN wake-up time < 100 ms. The init values to be used after power-up are defined in the LDF-files provided by Webasto and listed in the chapter LINinterface. Within each LIN-Signal description the power-upvalue is defined.
 
Paul, we added a serialprint line to the code on the lin.response which adds one digit to the printout. In my case it is a -1 which confirms no action on the heater, right?

Code:
#include "lin_bus.h"

uint16_t Power = 175;      // set to required power
uint8_t Temperature = 45;  // set to required temperature

LIN lin;

int lin_cs = 32;
uint8_t linTXdata[4] = { uint8_t(Power / 40), uint8_t(Temperature + 40), 0, 8 };
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);

  lin.begin(&Serial3, 9600); 
  //lin.begin(&Serial3, 19200);
}

void loop() {
  lin.order(21, linTXdata, 4, lin2x);     // set power, temp and heater ON  // 9600: 21 instead of 35
  delay(100);
  //lin.response(22, linRXdata, 8, lin2x);  // read the data from the HVH     // 9600: 22 instead of 24
  Serial.println(lin.response(22, linRXdata, 8, lin2x));
  for (int i = 0; i < 8; i++) {           // display the raw data
    Serial.println(linRXdata[i], HEX);
    delay(100);
  }
  digitalToggle(LED_BUILTIN);
  delay(100);
}

-1
0
9C
16
0
20
8
0
 
Paul, we added a serialprint line to the code on the lin.response which adds one digit to the printout. In my case it is a -1 which confirms no action on the heater, right?
I believe so. If I understand the library correctly, it returns -1 when the CRC is not correct. See this line.
Forum member @Markus_L811 is the author of the library. Perhaps he can confirm.

Paul
 
Thanks Paul. That makes sense. I appreciate the link to the line. I was wondering if we should take a step back and retrace the steps taken by Johan to first get a response at an ID and do a brute force program to go through all of the 256 IDs and see which returns something. Sending out the 8 to see if we get anything to return a 4????

Not sure if we could build off the GET FULL STATUS code for the RGB board.
 
I am sure I am mucking this up, but with the below code I am getting the following response with NOTHING hooked up:


HVH Full Status Demo

1
FFFFFFFF
0
58
18
0
20
8
0
0

2
FFFFFFFF
0
58
18
0
20
8
0
0

Code:
#include "lin_bus.h"

uint16_t Power = 175;      // set to required power
uint8_t Temperature = 45;  // set to required temperature

// 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

//#define DIAGNOSTIC_FRAME_SLAVE  0x55

LIN lin;
int lin_cs = 32;
int led1 = 23;
int lin_fault = 28;

uint8_t linTXdata[4] = { 0, 0, 0, 0 };
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
byte id = 0;

//void get_HVH50_full_status(id, linRXdata, 8) {

  //Serial.print("CRC: ");
  //Serial.println(lin.response(DIAGNOSTIC_FRAME_SLAVE, linRXdata, length),HEX);
//}
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault,INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);

  lin.begin(&Serial3, 9600);
  //lin.begin(&Serial3, 19200);

  delay(1000);
  pinMode(led1,OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
 
  Serial.begin(115200);
  Serial.println("HVH Full Status Demo");

    myTimer.begin(blinkLED, interval);
}

void loop() {
  //get_HVH50_full_status(id, linTXdata, 4, lin2x);     // set power, temp and heater ON  // 9600: 21 instead of 35
  //delay(3000);
  //lin.response(22, linRXdata, 8, lin2x);  // read the data from the HVH     // 9600: 22 instead of 24
  if (id < 256 ) {id++;}
   //Serial.print(lin.response(id, linRXdata, 8,lin2x ));
   //Serial.print("CRC: ");
   Serial.println(id);
   Serial.println(lin.response(id, linRXdata, 8),HEX);
for (int i = 0; i < 8; i++) {           // display the raw data
  //if (linRXdata[i] <8)
    //Serial.println("0");
    Serial.println(linRXdata[i], HEX);
    Serial.println(" ");
    //delay(100);
  digitalToggle(LED_BUILTIN);
  delay(100);
}

//void frame(uint8_t* data, uint8_t length) {
//  for (int i=0; i<length; i++) {
 // for (int i = 0; i < 8; i++) { 
//    if (data[i] < 0x55)
  //if (data[i] <8)
      //Serial.print("0");
    
    //Serial.print(data[i], HEX);
    //Serial.print(" ");
 // }
 // Serial.println();
}

void blinkLED() {
  ledState = !ledState;
 
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}
 
I am sure I am mucking this up, but with the below code I am getting the following response with NOTHING hooked up:
If I read your last code correctly, you never issued a lin.order(21, linTXdata, 4, lin2x); to turn the HVH on.
You need to use uint8_t linTXdata[4] = { uint8_t(Power / 40), uint8_t(Temperature + 40), 0, 8 }; as well to make that work.

Hmm, I feel we have to work with a lot of uncertainties: [1] are the HVH's operational, [2] which baudrate are they using, [3] is the table correct and complete, [4] do we have all necessary information.
Especially the last one: I would like to know which commands need to be issued in which sequence and at what timing to turn the HVH on. Do you happen to have more pages of info besides the 2 pages in Webasto LIN (English).pdf.

Just curious: did you also hookup the HV connector to the HVH50? I was wondering whether that would be necessary too to have the HVH50 to function properly.
Anyway, just keep trying.

Paul
 
Hi Paul. Thanks for the additional info on the linTXdata.

On the other points, I can address some of them. HV is connected when testing. Not all the time, but I do have it hooked up to the heater and can turn on the car to engage it. I usually test with LV or HV and then with just LV and then finally with LV and HV.

1708282398349.png


[1] are the HVH's operational

I believe so because I have 2 to pull from and it seems unlikely both would be bad. Also, I bought a 3rd one a while back and took it apart to examine the circuit board and have used that one to test LV and it seems to send 12V and LIN voltage to certain parts of the board when hooked up.

1708282444048.png


[2] which baudrate are they using,

I agree that this is troubling. Swapping between 9600 and 19200 is not ideal. I wonder if there is a simple standalone SKETCH out there to return the baud rate on the heater. This would certainly make things easier.

[3] is the table correct and complete

I am relying on the work done by Open Inverter and their successful engagement of the heater and hot water in STM32. However, I think if we wanted to go back to scratch and do this the same way they did, we would need to write a sketch to do what they did:

So it seems that units firmware has been altered for the OEM. It runs on 9600 (as opposed to 19200 in the manual) and replies to IDs 22 and 23 (PID 0xD6 and 0x97) as opposed to IDs 24 and 40. Now remains the question which one is the control ID (35 in the manual) and is the same data format still used. I sent this on all valid and invalid IDs. Also added an extra 0 byte or an upcounter in the 4th byte. No change, never drawing power. Then I got desperate and brute forced all values from 0-0xFF with incrementing PID and frame length. As soon as the heater reports a status != 0 I stop. When I hit ID22 it stopped with a "Temporary lock" probably because of collision as 22 is a read command. There is one documented status field in the first 3 bits of PID 0x97/23. It is 0 in stop mode, then has various error values and when it is 4 we are in operate mode. I have never seen it change though! Except once when I had appended data to the ID 22 READ request. There is another fast changing field in the last byte of PID 0xD6/22. But it always toggles between the same values even if I just read data. I changed my brute force attack, now it just tried all permutations of 0,1,2,4,...,128 on all 4 bytes and on all PIDs with length ranging from 1 to 4. That went much quicker, 0-0xFF would have taken days. But no combination was found that would change the status to "Operate". I monitored the first diagnostic status byte while sending some random data to all PIDs. Then at PID 0x55/21 the bit jumped to the supposed "Temporary Lock" value. Same for 22 and 23. So since 21 doesn't return any data it must be the command message. Now it was easy. I increased the length from 3 to 4 and there was no more Temporary Lock when sending on PID 21. I put values into the 4 bytes until the heater turned on.
Now, to summarize:
- Only 12V and LIN needs to be connected, interlock needn't be connected to anything.
- Byte 0 sets the power with a scaling factor of 40
- Byte 1 set the temperature setpoint in °C with an offset of 40
- Byte 2 is unused
- Byte 3 =8 heater on (i.e. bit 3 set)

[4] do we have all necessary information.

Here is the link to the whole PDF.
https://openinverter.org/forum/download/file.php?id=8774&sid=83ddd858437a39695647d538e0a552b9

I would just like to get some response from the heater
 
Back
Top