Webasto HVH50

Introduction and miscellaneous that we haven't created categories for, yet
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

OK. So I solved the Serial Plotter issue by asking for help on the Teensy forum and after some troubleshooting, I just needed to move a set of braces and edit the serial print commands. Updated code attached.
Teensy_LIN_bus_heater_V2.ino
(2.05 KiB) Downloaded 29 times
So now I am seeing Power, Temp and UDC but they are staying static at ZERO so something is still off on the programming I assume. No feedback. I tried at both 9600 and 19200.
image.png

Code: Select all

#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 Power = 175; // set to required power
uint8_t Temperature = 45; //set to required temperature
uint16_t tmpheater = 0;
uint16_t udcheater = 0;
uint16_t powerheater = 0;

LIN lin;

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

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);
  
  //Serial.begin(19200);
  //Serial.print("HVH50 Heater demo");
  
  myTimer.begin(blinkLED, interval);

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

void loop() {
  // heater
  SendLin();
  delay(100); // wait 100ms
  //Serial.print(" Heater test\n");
}

void blinkLED() {
  ledState = !ledState;
  
  digitalWrite(LED_BUILTIN, ledState);
}

  static void SendLin()
{
   static bool read = true;
   uint8_t data[8];
  if (lin.response(22, data, 8) >=0) // -1 indicates crc error, 9600
  //if (lin.response(24, data, 8) >=0) /// Change to this for 19200 /////
     {
     tmpheater = data[1] - 40;
     udcheater = data[4] | (data[5] & 3) << 8;
     powerheater =((data[5] >> 2) | (data[6] << 8)) * 20;
     }
     Serial.print("Temp:");
     Serial.print(tmpheater);
     Serial.print(",");
     Serial.print("Udc:");
     Serial.print(udcheater);
     Serial.print(",");
     Serial.print("Power:");
     Serial.println(powerheater);
      
   if (read)
   {
      lin.order(22, 0, 0); // 9600
      //lin.order(24, 0, 0); /// Change to this for 19200 /////
   }
   else
   {
	    uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
		  lin.order(21, lindata, 4); // this for 9600
      //lin.order(35, lindata, 4); /// Change to this for 19200 /////
      //Serial.print("\n Sending power and temperature");
   }

   read = !read;
}
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Actually, I am now realizing that my new code certainly puts the UDC, POWER and TEMP into the PLOTTER at all times, but that undoes the reason for the IF command.

I assume that the original placement of the braces was intended such that is a FALSE response was returned, nothing would show up in the PLOTTER. If I am right about this, then I must be receiving a FALSE response.

If so, I guess we need to look at why the send LIN command is not working . . .

Code: Select all

}

  static void SendLin()
{
   static bool read = true;
   uint8_t data[8];
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Hi guys. So I spent most of the day troubleshooting the heater with the help of one of the members of the Teensy forum (Paul). It was very helpful. Some things we learned today.

In the Webasto LIN document you attached in message #32, I see this:
1707598924472.png
HVH shall be a LIN slave node following the LIN specification package 2.1. Paul believed that this means that we have to tell the library to calculate the Enhanced Checksum by adding the "lin2x" parameter. So I updated the code with this information

Code: Select all

#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 Power = 175; // set to required power
uint8_t Temperature = 100; //set to required temperature
uint16_t tmpheater = 0;
uint16_t udcheater = 0;
uint16_t powerheater = 0;

LIN lin;

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

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);
  
  //Serial.begin(19200);
  //Serial.print("HVH50 Heater demo");
  
  myTimer.begin(blinkLED, interval);

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

void loop() {
  // heater
  SendLin();
  delay(100); // wait 100ms
  //Serial.print(" Heater test\n");
}

void blinkLED() {
  ledState = !ledState;
  
  digitalWrite(LED_BUILTIN, ledState);
}

  static void SendLin()
{
   static bool read = true;
   uint8_t data[8];
   delay(1000); // wait 1000ms
  if (lin.response(22, data, 8, lin2x) >=0) // -1 indicates crc error, 9600
  //if (lin.response(24, data, 8, lin2x) >=0) /// Change to this for 19200 /////
     {
     tmpheater = data[1] - 40;
     udcheater = data[4] | (data[5] & 3) << 8;
     powerheater =((data[5] >> 2) | (data[6] << 8)) * 20;
     Serial.print("Temp:");
     Serial.print(tmpheater);
     Serial.print(",");
     Serial.print("Udc:");
     Serial.print(udcheater);
     Serial.print(",");
     Serial.print("Power:");
     Serial.println(powerheater);
     }
   //if (read)
   //{
      //lin.order(22, 0, 0, lin2x); // 9600
      //lin.order(24, 0, 0, lin2x); /// Change to this for 19200 /////
   //}
   else
   {
	    uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
		  lin.order(21, lindata, 4, lin2x); // this for 9600
      //lin.order(35, lindata, 4, lin2x); /// Change to this for 19200 /////
      //Serial.print("\n Sending power and temperature");
   }

   read = !read;
}
It seemed to get the board to open up the 3.3V on pins 2 and 4 on the MCP2004 chip.
1707596888271.png
1707596888271.png (23.02 KiB) Viewed 1157 times
STILL NO HOT WATER!

We worked up a short program to see what response we were getting from sending the 8 for power.

Code: Select all

#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);
  Serial.println(lin.response(22, data, 8, lin2x), HEX);
  digitalToggle(LED_BUILTIN);
  delay(100);
}
When we ran this program, the SERIAL MONITOR received feed back of:

FFFFFFFF

0xFFFFFFFF means that it is reading HIGH's only. HIGH is the default state of the DATA line. And 0xFFFFFFFF is only 4 bytes - you would expect lin.response(22, data, 8, lin2x to read 8 bytes.

Paul from the TEENSY FORUM also wondered why we actually need the lin.order(24, 0, 0, lin2x);? ID24 is a read-register, so why do we need to write "0,0"? He suggested I comment out lin.order(24, 0, 0, lin2x); in the code. Wondered if you had any thoughts about this as well.


Any thoughts on any of this? I feel I am very close, but just missing something.
royhen99
Posts: 211
Joined: Sun Feb 20, 2022 4:23 am
Location: N. Wiltshire. UK
Has thanked: 16 times
Been thanked: 101 times

Re: Webasto HVH50

Post by royhen99 »

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.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

thanks for the response and explanation of the FFFFFFFF response. So if I am getting the -1 response, what are my options to troubleshoot?

I am trying both baud rates with the 22 @ 9600 and 24 @ 19200.

I will restore the lin.order command on your explanation of why it is needed.

I am glad your transceiver is working with the lin2x fix. Are you using the Teensy board or something else?

Are you getting heated water?

Is there a simpler program that would just tell me if I am getting connection to the heater?
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

OK . . . so Paul suggested I revise the code as follows:

Code: Select all

#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);
}
This yielded a different response from the FFFFFFFF
image.png
and the plotter shows this:
image.png
So I am wondering what this means to you. I got these same readings with and without the heater connected and powered on and off and same results in 9600 and 19200 modes.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

hello royhen99. I was hoping to pick this back up. I have now been able to test the teensy and breakout board with a slave RGB board and LIN is being transmitted to make the slave board LED go Green, Blue and Red. Here is that working code.

Code: Select all

/*

 *

 * Teensy 4.0 CAN FD and LIN-bus demo.

 *

 * For use with this board:

 * https://www.skpang.co.uk/products/teensy-4-0-can-fd-and-lin-bus-breakout-board-include-teensy-4-0

 *

 * LIN-bus library must be installed first.

 * https://github.com/MarkusLange/Teensy_3.x_4.x_and_LC_LIN_Master

 *

 * NCV7430 RGB board:

 * https://www.skpang.co.uk/collections/breakout-boards/products/ncv7430-lin-bus-rgb-led-breakout-baord

 *

 */



#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



#define SET_LED_CONTROL 0x23

#define SET_LED_COLOUR  0x24



//LIN lin(&Serial3, 19200);

LIN lin;

int lin_cs = 32;



int led1 = 23;

int lin_fault = 28;

//                              Grp   Grp   Fade  Intense  G     R     B

uint8_t buffer_red[]   = {0xc0, 0x00, 0x00, 0x00, 0x31, 0x00, 0xff, 0x00};

uint8_t buffer_green[] = {0xc0, 0x00, 0x00, 0x00, 0x31, 0xff, 0x00, 0x00};

uint8_t buffer_blue[]  = {0xc0, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0xff};





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, 19200);



  delay(1000);

  pinMode(led1,OUTPUT);

    digitalWrite(LED_BUILTIN, LOW);



  Serial.begin(115200);

  Serial.print("NVC7430 RGB Demo");



  init_ncv7430();

  myTimer.begin(blinkLED, interval);



}

void loop() {

  // Red

  Serial.println("red");

  set_nvc7430_color(buffer_red);

  delay(500);

 

  // Green

  Serial.println("green");

  set_nvc7430_color(buffer_green);

  delay(500);

 

  // Blue

  Serial.println("blue");

  set_nvc7430_color(buffer_blue);

  delay(500);

}



void init_ncv7430(void) {

  uint8_t control_buffer[] = {0xc0, 0x00, 0x00, 0x7f};

 

  lin.order(SET_LED_CONTROL, control_buffer, 4);

}



void set_nvc7430_color(byte* message) {

  lin.order(SET_LED_COLOUR, message, 8);

}



void blinkLED() {

  ledState = !ledState;

 

  digitalWrite(LED_BUILTIN, ledState);

  digitalWrite(led1, ledState);

}

I am still not getting hot water from the heater, so I assume something in your coding is not telling the heater to turn on. I am trying to understand the If Else code below.

Code: Select all

 if (lin.response(22, data, 8, lin2x) >=0) // -1 indicates crc error, 9600
  //if (lin.response(24, data, 8, lin2x) >=0) /// Change to this for 19200 /////
     {
     tmpheater = data[1] - 40;
     udcheater = data[4] | (data[5] & 3) << 8;
     powerheater =((data[5] >> 2) | (data[6] << 8)) * 20;
     Serial.print("Temp:");
     Serial.print(tmpheater);
     Serial.print(",");
     Serial.print("Udc:");
     Serial.print(udcheater);
     Serial.print(",");
     Serial.print("Power:");
     Serial.println(powerheater);
     }
   if (read)
   {
      lin.order(22, 0, 0, lin2x); // 9600
      //lin.order(24, 0, 0, lin2x); /// Change to this for 19200 /////
   }
   else
   {
	    uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
		  lin.order(21, lindata, 4, lin2x); // this for 9600
      //lin.order(35, lindata, 4, lin2x); /// Change to this for 19200 /////
      //Serial.print("\n Sending power and temperature");
   }
Can you help me understand the reason for the second IF command and also why there is no action to be taken if the statement is true?

Also, should we not be sending commands to ID 21 instead of ID 22 based on 21 being write power and 22 being read measure and 23 being read status?
royhen99
Posts: 211
Joined: Sun Feb 20, 2022 4:23 am
Location: N. Wiltshire. UK
Has thanked: 16 times
Been thanked: 101 times

Re: Webasto HVH50

Post by royhen99 »

Bear in mind I have very little experience of LIN bus, I do not have a HVH50, I am not very good at coding and there are no examples of using this libray for receive. My code was my best attempt at modifying johu's code to run on the Teensy.

As I expalined above to receive 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 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.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Thank you for the reply and I totally understand that you are shooting in the dark to some extent. My expertise is well below yours :D

I appreciate your continuing willingness to help. I will take this info back to the TEENSY Forum and see what they can add to help me cross the finish line and report back!
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

So based on the work done over here by you and Johan, the guys at the Teensy Forum put together a sketch with a feedback loop to see if we could get a reaction from the HVH.

I compiled and ran the below code in both 9600 and 19200 baud on both of my HVH heaters. With and without power I only got a response of:

Code: Select all

0
9C
16
0
20
8
0
0

Code: Select all

#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);
}
I assume I am looking for a 4 in the first position. Any other thoughts from anyone on here about why the heater is not reacting to the lin commands?

I am not doing anything with the HV and LV interlocks.

Also, I am testing it with and without HV running. I assume with 12V and LIN (but no HV), I should still get a response of 4 to the heater being on, right?

Also, just to be sure, with an scaling factor of 40 on the POWER, if I set to 175, I should be getting 7000W available power right?
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

image.png
image.png
espriev
Posts: 44
Joined: Mon Jan 02, 2023 5:32 pm

Re: Webasto HVH50

Post by espriev »

I think that with no HV you will only receive a "not ready" response
The Webasto doc notes that the HV MUST employ a pre-charge
According to post 16 on page 1 no interlock is required, but it is easy enough to try, just jumper the interlock pins on the HV connector
User avatar
johu
Site Admin
Posts: 5791
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 157 times
Been thanked: 1024 times
Contact:

Re: Webasto HVH50

Post by johu »

espriev wrote: Sun Feb 18, 2024 4:52 pm According to post 16 on page 1 no interlock is required, but it is easy enough to try, just jumper the interlock pins on the HV connector
The interlock pins are just shorted internally and pass on whichever signal from one interlock pin to the other. No "intelligence" is connected to them
jsimonkeller wrote: Sat Feb 17, 2024 10:32 pm I assume I am looking for a 4 in the first position. Any other thoughts from anyone on here about why the heater is not reacting to the lin commands?
As far as I see you still haven't really confirmed that there is ANY communication going on, right? Can you scope the LIN signal?

BTW have you solidly grounded the HVA via the ground stud and also connected up the grounds of your Teensy and the HVH?
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

johu wrote: Sun Feb 18, 2024 6:14 pm BTW have you solidly grounded the HVA via the ground stud and also connected up the grounds of your Teensy and the HVH?
Yes, the post on the HVH is grounded as well as the teensy. Besides the outer grounding post on the HVH (circled in green), is there another ground wire you are referring to? When the post is grounded, I notice that wire 8 from the harness (circled in red) has a ground signal, so I assume that tells me the unit is grounded.
PXL_20240218_0039096482.jpg
johu wrote: Sun Feb 18, 2024 6:14 pm The interlock pins are just shorted internally and pass on whichever signal from one interlock pin to the other. No "intelligence" is connected to them
That is how I am proceeding by not connecting the interlock wires.
espriev wrote: Sun Feb 18, 2024 4:52 pm HV MUST employ a pre-charge
I have been testing with HV on, but not always. If HV is a pre-req to even get a heater on response of 4, then I will note that going forward on future testing.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Johan, while I continue troubleshooting my issues, I wanted to ask a few questions:

1. Was your Webasto heater from a Volvo? Do you recall the year? If you still have the heater on hand, can you post a picture of the heater and label?

2. For power and temp settings, I was using 175 and 45. Am I doing this right? Scaling factor of 40 * 175 = 7000W and 45 C +40 =85C temp. I wanted to rule out future issues.

3. When you were running your testing, were you just grounding the post on the outside of the heater with no other wires into the heater being grounded?

4. Heater manual says It can be driven with voltages between 100 – 450 V DC. Do you recall your input voltage while testing it?

Thanks!
royhen99
Posts: 211
Joined: Sun Feb 20, 2022 4:23 am
Location: N. Wiltshire. UK
Has thanked: 16 times
Been thanked: 101 times

Re: Webasto HVH50

Post by royhen99 »

jsimonkeller wrote: Mon Feb 19, 2024 2:03 pm 2. For power and temp settings, I was using 175 and 45. Am I doing this right? Scaling factor of 40 * 175 = 7000W and 45 C +40 =85C temp. I wanted to rule out future issues.
The scaling is for the value sent/received over linbus. Just set the temperature and power that you require. Power is in steps of 40W so 175 is actually 160W as the /40 gives an integer result.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Thanks!
royhen99 wrote: Mon Feb 19, 2024 2:37 pm Just set the temperature and power that you require.
So the below would be correct if I wanted 5000W of power and 85 degree water temp?

uint16_t Power = 5000; // set to required power
uint8_t Temperature = 85; //set to required temperature

I don't know why I thought I needed to adjust, but thanks for clarifying. One less thing to be mucking up my heater work!
User avatar
johu
Site Admin
Posts: 5791
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 157 times
Been thanked: 1024 times
Contact:

Re: Webasto HVH50

Post by johu »

jsimonkeller wrote: Mon Feb 19, 2024 2:03 pm Was your Webasto heater from a Volvo
Can't figure that one out, the customer had bought it off ebay
jsimonkeller wrote: Mon Feb 19, 2024 2:03 pm When you were running your testing, were you just grounding the post on the outside of the heater with no other wires into the heater being grounded?
Yes
jsimonkeller wrote: Mon Feb 19, 2024 2:03 pm Do you recall your input voltage while testing it?
Tested at 290V (see beginning of thread)
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

As way of an update, I got my Oscilloscope and was able to at least see the LIN command is going out to the HVH with no response.
image.png
Updated code for a CRC response and still getting -1
image.png
I assume it could not be something in the CPP file that is not working as it should, but here is that code:

Code: Select all

#include "Arduino.h"
#include "lin_bus.h"

void LIN::begin(HardwareSerial* stream, uint16_t baudrate, uint8_t break_characters) {
  (*stream).begin(baudrate);
  this->_stream = stream;
  
  Tbit = 1000000/baudrate;
  responsespace = responsedelay*Tbit;
  interbytespace = interbytedelay*Tbit;
  syncfieldPIDinterbytespace = syncfieldPIDinterbytedelay*Tbit;
  breakfieldinterbytespace = breakfieldinterbytedelay*Tbit;
  response_nominalspace = response_nominal*Tbit;
  response_maximalspace = response_nominalspace*response_max_factor;
  
  if (stream == &Serial1) {
#if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__)
    PortRegister_C1 = &UART0_C1;
    PortRegister_C2 = &UART0_C2;
    PortRegister_C4 = &UART0_C4;
    PortRegister_S2 = &UART0_S2;
    PortRegister_BDH = &UART0_BDH;
#ifdef HAS_KINETISK_UART0_FIFO
    UART0_RWFIFO = 1;
#endif // HAS_KINETISK_UART0_FIFO
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    PortRegister_LPUART_STAT = &LPUART6_STAT;
    PortRegister_LPUART_BAUD = &LPUART6_BAUD;
    PortRegister_LPUART_CTRL = &LPUART6_CTRL;
#endif
  }

  if (stream == &Serial2) {
#if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__)
    PortRegister_C1 = &UART1_C1;
    PortRegister_C2 = &UART1_C2;
    PortRegister_C4 = &UART1_C4;
    PortRegister_S2 = &UART1_S2;
    PortRegister_BDH = &UART1_BDH;
#ifdef HAS_KINETISK_UART1_FIFO
    UART1_RWFIFO = 1;
#endif // HAS_KINETISK_UART0_FIFO
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    PortRegister_LPUART_STAT = &LPUART4_STAT;
    PortRegister_LPUART_BAUD = &LPUART4_BAUD;
    PortRegister_LPUART_CTRL = &LPUART4_CTRL;
#endif
  }
  
  if (stream == &Serial3) {
#if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__)
    PortRegister_C1 = &UART2_C1;
    PortRegister_C2 = &UART2_C2;
    PortRegister_C4 = &UART2_C4;
    PortRegister_S2 = &UART2_S2;
    PortRegister_BDH = &UART2_BDH;
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    PortRegister_LPUART_STAT = &LPUART2_STAT;
    PortRegister_LPUART_BAUD = &LPUART2_BAUD;
    PortRegister_LPUART_CTRL = &LPUART2_CTRL;
#endif
  }

#if defined (__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
  if (stream == &Serial4) {
#if defined (__MK64FX512__) || defined(__MK66FX1M0__)
    PortRegister_C1 = &UART3_C1;
    PortRegister_C2 = &UART3_C2;
    PortRegister_C4 = &UART3_C4;
    PortRegister_S2 = &UART3_S2;
    PortRegister_BDH = &UART3_BDH;
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    PortRegister_LPUART_STAT = &LPUART3_STAT;
    PortRegister_LPUART_BAUD = &LPUART3_BAUD;
    PortRegister_LPUART_CTRL = &LPUART3_CTRL;
#endif
  }
  
  if (stream == &Serial5) {
#if defined (__MK64FX512__) || defined(__MK66FX1M0__)
    PortRegister_C1 = &UART4_C1;
    PortRegister_C2 = &UART4_C2;
    PortRegister_C4 = &UART4_C4;
    PortRegister_S2 = &UART4_S2;
    PortRegister_BDH = &UART4_BDH;
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    PortRegister_LPUART_STAT = &LPUART8_STAT;
    PortRegister_LPUART_BAUD = &LPUART8_BAUD;
    PortRegister_LPUART_CTRL = &LPUART8_CTRL;
#endif
  }
  
  if (stream == &Serial6) {
#if defined (__MK64FX512__)
    PortRegister_C1 = &UART5_C1;
    PortRegister_C2 = &UART5_C2;
    PortRegister_C4 = &UART5_C4;
    PortRegister_S2 = &UART5_S2;
    PortRegister_BDH = &UART5_BDH;
#elif defined(__MK66FX1M0__)
    PortRegister_LPUART_STAT = &LPUART0_STAT;
    PortRegister_LPUART_BAUD = &LPUART0_BAUD;
    PortRegister_LPUART_CTRL = &LPUART0_CTRL;
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    PortRegister_LPUART_STAT = &LPUART1_STAT;
    PortRegister_LPUART_BAUD = &LPUART1_BAUD;
    PortRegister_LPUART_CTRL = &LPUART1_CTRL;
#endif
  }
#endif

#if defined(__IMXRT1062__) // Teensy 4.0 & 4.1
  if (stream == &Serial7) {
    PortRegister_LPUART_STAT = &LPUART7_STAT;
    PortRegister_LPUART_BAUD = &LPUART7_BAUD;
    PortRegister_LPUART_CTRL = &LPUART7_CTRL;
  }
#endif

#if defined(__IMXRT1062__) && defined(ARDUINO_TEENSY41) // Teensy 4.1
  if (stream == &Serial8) {
    PortRegister_LPUART_STAT = &LPUART5_STAT;
    PortRegister_LPUART_BAUD = &LPUART5_BAUD;
    PortRegister_LPUART_CTRL = &LPUART5_CTRL;
  }
#endif

#if defined (__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 & 3.2
  breaklength(break_characters);
#elif defined (__MK64FX512__) // Teensy 3.5
  breaklength_35(break_characters);
#elif defined (__MK66FX1M0__) // Teensy 3.6
  if (stream == &Serial6)
    breaklength_LP(break_characters);
  else
    breaklength_35(break_characters);
#elif defined (__MKL26Z64__) // Teensy LC
  breaklength_LC(break_characters, stream);
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
  breaklength_LP(break_characters);
#endif
}

void LIN::breaklength_LP(uint8_t length) {
  switch (length) {
#if defined(__IMXRT1062__) // Teensy 4.0 & 4.1
    case  9:
      //  9 Bits transmitted
      (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10;
      (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_M7;
#endif
    case 10:
      // 10 Bits transmitted
      (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10;
#if defined(__IMXRT1062__) // Teensy 4.0 & 4.1
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M7;
#endif
      break;
    case 11:
      // 11 Bits transmitted
      (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10;
#if defined(__IMXRT1062__) // Teensy 4.0 & 4.1
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M7;
#endif
      break;
    case 12:
      // 12 Bits transmitted
      (*PortRegister_LPUART_STAT) &= ~LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_M;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10;
      break;
    case 13:
      // 13 Bits transmitted
      (*PortRegister_LPUART_STAT) |= LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10;
#if defined(__IMXRT1062__) // Teensy 4.0 & 4.1
      (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_M7;
#endif
      break;
    case 14:
      // 14 Bits transmitted
      (*PortRegister_LPUART_STAT) |= LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_M;
      (*PortRegister_LPUART_BAUD) &= ~LPUART_BAUD_M10;
      break;
    case 15:
      // 15 Bits transmitted
      (*PortRegister_LPUART_STAT) |= LPUART_STAT_BRK13;
      (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_SBNS;
      (*PortRegister_LPUART_BAUD) |= LPUART_BAUD_M10;
      break;
  }
}

#if defined (__MK20DX128__) || defined(__MK20DX256__) || (__MKL26Z64__) || (__MK64FX512__) || (__MK66FX1M0__)
void LIN::breaklength_35(uint8_t length) {
  switch (length) {
    case 10:
      // 10 Bits transmitted
      (*PortRegister_S2)  &= ~UART_S2_BRK13;
      (*PortRegister_BDH) &= ~UART_BDH_SBNS;
      (*PortRegister_C1)  &= ~UART_C1_M;
      break;
    case 11:
      // 11 Bits transmitted
      (*PortRegister_S2)  &= ~UART_S2_BRK13;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      (*PortRegister_C1)  &= ~UART_C1_M;
      break;
    case 12:
      // 12 Bits transmitted
      (*PortRegister_S2)  &= ~UART_S2_BRK13;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      (*PortRegister_C1)  |= UART_C1_M;
      (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 13:
      // 13 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_BDH) &= ~UART_BDH_SBNS;
      (*PortRegister_C1)  &= ~UART_C1_M;
      break;
    case 14:
      // 14 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_BDH) &= ~UART_BDH_SBNS;
      (*PortRegister_C1)  |= UART_C1_M;
      break;
    case 15:
      // 15 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      (*PortRegister_C1)  &= ~UART_C1_M;
      break;
    case 16:
      // 16 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      (*PortRegister_C1)  |= UART_C1_M;
      break;
  }
}

void LIN::breaklength_LC(uint8_t length, HardwareSerial* stream) {
  switch (length) {
    case 10:
      // 10 Bits transmitted
      (*PortRegister_S2)  &= ~UART_S2_BRK13;
      (*PortRegister_C1)  &= ~UART_C1_M;
      (*PortRegister_BDH) &= ~UART_BDH_SBNS; 
      if (stream == &Serial1)
        (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 11:
      // 11 Bits transmitted
      (*PortRegister_S2)  &= ~UART_S2_BRK13;
      (*PortRegister_C1)  &= ~UART_C1_M;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      if (stream == &Serial1)
        (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 12:
      // 12 Bits transmitted
      (*PortRegister_S2)  &= ~UART_S2_BRK13;
      (*PortRegister_C1)  |= UART_C1_M;
      (*PortRegister_BDH) |= UART_BDH_SBNS;  
      if (stream == &Serial1)
        (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 13:
      // 13 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_C1)  &= ~UART_C1_M;
      (*PortRegister_BDH) &= ~UART_BDH_SBNS;
      if (stream == &Serial1)
        (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 14:
      // 14 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_C1)  &= ~UART_C1_M;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      if (stream == &Serial1)
        (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 15:
      // 15 Bits transmitted
      (*PortRegister_S2)  |= UART_S2_BRK13;
      (*PortRegister_C1)  |= UART_C1_M;
      (*PortRegister_BDH) |= UART_BDH_SBNS;
      if (stream == &Serial1)
        (*PortRegister_C4)  &= ~UART_C4_M10;
      break;
    case 16:
      // 16 Bits transmitted
      if (stream == &Serial1) {
        (*PortRegister_S2)  |= UART_S2_BRK13;
        (*PortRegister_C4)  |= UART_C4_M10;
        (*PortRegister_BDH) |= UART_BDH_SBNS;
      }
      break;
  }
}

void LIN::breaklength(uint8_t length) {
  switch (length) {
    case 10:
      // 10 Bits transmitted
      (*PortRegister_S2) &= ~UART_S2_BRK13;
      (*PortRegister_C1) &= ~UART_C1_M;
      break;
    case 11:
      // 11 Bits transmitted
      (*PortRegister_S2) &= ~UART_S2_BRK13;
      (*PortRegister_C1) |= UART_C1_M;
      (*PortRegister_C4) &= ~UART_C4_M10;
      break;
    case 12:
      // 12 Bits transmitted
      (*PortRegister_S2) &= ~UART_S2_BRK13;
      (*PortRegister_C1) |= UART_C1_M;
      (*PortRegister_C4) |= UART_C4_M10;
      (*PortRegister_C1) |= UART_C1_PE;
      break;
    case 13:
      // 13 Bits transmitted
      (*PortRegister_S2) |= UART_S2_BRK13;
      (*PortRegister_C1) &= ~UART_C1_M;
      break;
    case 14:
      // 14 Bits transmitted
      (*PortRegister_S2) |= UART_S2_BRK13;
      (*PortRegister_C1) |= UART_C1_M;
      break;
  }
}
#endif

int LIN::addrParity(int PID) {
  int P0 = ((PID>>0) + (PID>>1) + (PID>>2) + (PID>>4)) & 1;
  int P1 = ~((PID>>1) + (PID>>3) + (PID>>4) + (PID>>5)) & 1;
  return (P0 | (P1<<1));
}

//sum = 0 LIN 1.X CRC, sum = PID LIN 2.X CRC Enhanced
volatile byte LIN::dataChecksum(volatile byte* message, int length, uint16_t sum) {
  for (int i=0; i<length; i++) {
    sum += message[i];
    
    if (sum >= 256)
      sum -= 255;
  }
  return (~sum);
}

void LIN::send_break() {  
  // Toggle SBK to send Break
  //UART0_C2 |= UART_C2_SBK;
  //UART0_C2 &= ~UART_C2_SBK;
  
#if defined(__MK66FX1M0__) // Teensy 3.6
  if (_stream == &Serial6) {
    (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_SBK;
    (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_SBK;
  } else {
    (*PortRegister_C2) |= UART_C2_SBK;
    (*PortRegister_C2) &= ~UART_C2_SBK;
  }
#elif defined (__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MKL26Z64__) || defined(__MK66FX1M0__) // Teensy 3.0 & 3.1 & 3.2 & 3.5
  (*PortRegister_C2) |= UART_C2_SBK;
  (*PortRegister_C2) &= ~UART_C2_SBK;
#elif defined(__IMXRT1062__) // Teensy 4.0 & 4.1
  (*PortRegister_LPUART_CTRL) |= LPUART_CTRL_SBK;
  (*PortRegister_LPUART_CTRL) &= ~LPUART_CTRL_SBK;
#endif

/*
#if defined (__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MKL26Z64__) // Teensy 3.0 & 3.1 & 3.2 & 3.5
  (*PortRegister_C2) |= UART_C2_SBK;
  (*PortRegister_C2) &= ~UART_C2_SBK;
#elif defined(__MK66FX1M0__) // Teensy 3.6
//  #ifdef HAS_KINETISK_UART5
  if (LPU == 1) {
    LPUART0_CTRL |= LPUART_CTRL_SBK;
    LPUART0_CTRL &= ~LPUART_CTRL_SBK;
	#pragma "Using KINETISK_LPUART0"
  } else {
//  #else
    (*PortRegister_C2) |= UART_C2_SBK;
    (*PortRegister_C2) &= ~UART_C2_SBK;
	#pragma "Using all other"
//  #endif
  }
#endif
*/

  _stream->write(SYNC);      //Sync 0x55
  _stream->flush();
  
  delayMicroseconds(syncfieldPIDinterbytespace);
}

void LIN::write(byte PID, byte* message, int length, int checksumtype) {
  byte CRC, send_pid;
  
  send_pid = ((PID&0x3F) | (addrParity(PID)<<6));
  
  if (checksumtype == 1)
    CRC = dataChecksum(message, length, 0);
  else
    CRC = dataChecksum(message, length, send_pid);
  
  _stream->write(send_pid);
  delayMicroseconds(breakfieldinterbytespace);
  
  for (int i = 0; i < length; i++)
    _stream->write(message[i]);
  
  _stream->write(CRC);
  _stream->flush();
}

void LIN::order(byte PID, byte* message, int length, int checksumtype) {
  send_break();
  write(PID, message, length, checksumtype);
}

int LIN::response(byte PID, byte message[], int length, int checksumtype) {
  //_stream->clear(); does not exist, this does the same!
  while(_stream->available() > 0) {
    _stream->read();
  }
  
  send_break();
  return read(PID, message, length, checksumtype);
}

int LIN::read(byte PID, byte* data, int length, int checksumtype) {
  byte CRC, send_pid;
  // +4 for Break, Sync, PID and CRC after the Data
  byte tmp[length+4];
  uint8_t i = 0;
  
  send_pid = ((PID&0x3F) | (addrParity(PID)<<6));
  
  _stream->write(send_pid);
  _stream->flush();
  
#if defined(__IMXRT1062__) // Teensy 4.0 & 4.1 clear Uart Buffer
  //_stream->read();
  //Serial.println(_stream->read(),HEX);
#endif
  
  /*
  unsigned long actuall = micros();
  
  while ( i < (length+4) ) {
    if ( _stream->available() ) {
      tmp[i] = _stream->read();
      Serial.println(tmp[i], HEX);
      i++;
    }
	if ( (actuall+response_maximalspace) > micros() ) {
	  break;
	}
  }
  */
  
  elapsedMicros waiting;
  //Serial.println(waiting);
  
  while ( i < (length+4) ) {
    if ( _stream->available() ) {
      tmp[i] = _stream->read();
      i++;
    }
    if ( response_maximalspace < waiting ) {
      break;
     }
  }
  //Serial.println(waiting);
  
  for ( i = 3; i < (length+3); i++)
    data[i-3] = tmp[i];
  
  if (checksumtype == 1)
    CRC = dataChecksum(data, length, 0);
  else
    CRC = dataChecksum(data, length, send_pid);
  
  /*
  Serial.println("--------tmp------------");
  for (i = 0; i < (length+4); i++)
    Serial.println(tmp[i], HEX);

  Serial.println("--------data-----------");
  for (i = 3; i < (length+3); i++)
	Serial.println(data[i-3],HEX);
  
  Serial.println("--------crc------------");
  Serial.println(CRC,HEX);
  Serial.println(tmp[length+3],HEX);
  Serial.println("-----------------------");
  */
  
  if (CRC == tmp[length+3])
    return CRC;
  else
    return -1;
}
I ordered one more HVH off ebay from a Volvo and will test when it arrives.

CURRENT LIN BUS HEATER CODE

Code: Select all

#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 Power = 5000; // set to required power
uint8_t Temperature = 85; //set to required temperature
uint16_t tmpheater = 0;
uint16_t udcheater = 0;
uint16_t powerheater = 0;

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[8];

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lin_fault,INPUT);
  pinMode(lin_cs, OUTPUT);
  digitalWrite(lin_cs, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);
  
  //Serial.begin(19200);
  //Serial.print("HVH50 Heater demo");
  
  lin.begin(&Serial3, 9600);
  //lin.begin(&Serial3, 19200); /// Change to this for 19200 /////
  
  delay(1000);
  pinMode(led1,OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
  
  myTimer.begin(blinkLED, interval);
}

void loop() {
  // heater
  SendLin();
  delay(1000); // wait 1000ms
  //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(1000); // wait 1000ms
   uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
	 lin.order(21, lindata, 4, lin2x); // this for 9600
   delay(100);
    Serial.print("CRC: ");
    Serial.println(lin.response(22, data, 8, lin2x));
  if (lin.response(22, data, 8, lin2x) >=0) // -1 indicates crc error, 9600
  //if (lin.response(24, data, 8, lin2x) >=0) /// Change to this for 19200 /////
     {
     tmpheater = data[1] - 40;
     udcheater = data[4] | (data[5] & 3) << 8;
     powerheater =((data[5] >> 2) | (data[6] << 8)) * 20;
     Serial.print("Temp:");
     Serial.print(tmpheater);
     Serial.print(",");
     Serial.print("Udc:");
     Serial.print(udcheater);
     Serial.print(",");
     Serial.print("Power:");
     Serial.println(powerheater);
     }
   else if (read)
   {
      lin.order(22, 0, 0, lin2x); // 9600
      //lin.order(24, 0, 0, lin2x); /// Change to this for 19200 /////
   }
   else
   {
	    uint8_t lindata[] = {uint8_t(Power/40), uint8_t(Temperature+40), 0, 8};
		  lin.order(21, lindata, 4, lin2x); // this for 9600
      //lin.order(35, lindata, 4, lin2x); /// Change to this for 19200 /////
      //Serial.print("\n Sending power and temperature");
   }

   read = !read;
}
User avatar
johu
Site Admin
Posts: 5791
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 157 times
Been thanked: 1024 times
Contact:

Re: Webasto HVH50

Post by johu »

I'd remove the code that sets heater power and only keep the code that queries the items (id 22 or 24, respectively). Only when you see the HVH responding to that will you have any chance to proceed further to send power requests
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Thanks Johan. I am still getting no response with 3 different heaters on the test bench... 300V . . . 12V and LIN connected . . . . grounded . . . I will certainly have extra to share when I finally crack this. :D

We wrote a shorter SKETCH to do what you suggested above. I know you said to take out the Order on 21 or 35, but don't we need to send something to get a response? I would be seriously surprised that the circuitry will react before sending a Power ON request first. That's how I would design it if I was a Webasto engineer...

Code: Select all

#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;
int CRC = 0;
int led1 = 23;
int lin_fault = 28;

uint8_t linTXdata[4] = { 1, 85, 0, 8 };  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 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);

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

    delay(1000);
  pinMode(led1,OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);

  myTimer.begin(blinkLED, interval);
}

void loop() {
  lin.order(21, linTXdata, 4);  // set power, temp and heater ON
  delay(1);
  lin.order(21, linTXdata, 4, lin2x);
  delay(1);
  lin.order(35, linTXdata, 4);
  delay(1);
  lin.order(35, linTXdata, 4, lin2x);

  delay(100);  //wait for HVH to wakeup

  CRC = lin.response(22, linRXdata, 8);
  Serial.print("ID 22, lin1x, CRC: ");
  Serial.println(CRC, HEX);
  delay(10);

  CRC = lin.response(24, linRXdata, 8);
  Serial.print("ID 24, lin1x, CRC: ");
  Serial.println(CRC, HEX);
  delay(10);

  CRC = lin.response(22, linRXdata, 8, lin2x);
  Serial.print("ID 22, lin2x, CRC: ");
  Serial.println(CRC, HEX);
  delay(10);

  CRC = lin.response(24, linRXdata, 8, lin2x);
  Serial.print("ID 24, lin2x, CRC: ");
  Serial.println(CRC, HEX);
  delay(10);

  delay(1000);
}
void blinkLED() {
  ledState = !ledState;
  
  digitalWrite(LED_BUILTIN, ledState);
  digitalWrite(led1, ledState);
}

Still just FFFFFFFF but we will try to expand to check other IDs.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

Another update on my saga.

We ran the below code to brute force all IDs on request and all IDs on reponse.

Code: Select all

#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;  // pin 23 for my LIN board
int led1 = 23;
int lin_fault = 28;

uint8_t linTXdata[4] = { 1, 85, 0, 8 };  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t CRC = 0;
uint8_t orderID = 0;
uint8_t responseID = 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);

  //lin.begin(&Serial3, 19200);  // or
  lin.begin(&Serial3, 9600);
  delay(1000);
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  for (orderID = 0; orderID < 64; orderID++) {
    for (responseID = 0; responseID < 64; responseID++) {

      lin.order(orderID, linTXdata, 4, lin2x);
      delay(100);

      CRC = lin.response(responseID, linRXdata, 8, lin2x);
      Serial.print(orderID, HEX);
      Serial.print("\t");
      Serial.print(responseID, HEX);
      Serial.print("\t");
      Serial.println(CRC, HEX);
      delay(100);
    }
  }
}
The result was a response at ID 39 on every ID that was ordered:
image.png
We modified the code to read out only ID 0x27

Code: Select all

#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;  // pin 23 for my LIN board
int led1 = 23;
int lin_fault = 28;

uint8_t linTXdata[4] = { 1, 85, 0, 8 };  // 40W, 45C, heater on
uint8_t linRXdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t CRC = 0;
uint8_t orderID = 0x00;
uint8_t responseID = 0x27;

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);

  lin.begin(&Serial3, 19200);
  delay(1000);
  pinMode(led1, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  lin.order(orderID, linTXdata, 4, lin2x);  // perhaps not needed?
  delay(100);
  CRC = lin.response(responseID, linRXdata, 8, lin2x);
  Serial.println(CRC, HEX);
  for (int i = 0; i < 8; i++) {  // display the raw data
    Serial.print(linRXdata[i], HEX);
    Serial.print("\t");
  }
  Serial.println();
  delay(100);
}
which resulted in this response:
image.png

Scope looked like this:
image.png
No responses on ox27, but mostly 0x3c and 0x3d which are the status IDs for the HVH in the manual:
8.5 UDS-Diagnosis
The standard LIN 2.1 Diagnosis frames (see LDF file Frame
ID 0x3C / 0x3D) will be used to map Universal Diagnosis
Services / Sub-Services and Data.
Not sure what to do with all of this information, but hoping someone has some thoughts on how to take what I have figured out today to the next step.

Thanks!
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

I converted back from Hex to Decimal to make it easier for me and when writing to all IDs but letting the response go through ID 39, I see that the data comes through as follows;

Code: Select all

0                           

0    62    0    124    61    80    0    207

0                           

0                           

0    62    0    123    61    80    0    208

1                           

0                           

0    62    0    123    61    80    0    208

2                           

0                           

0    62    0    123    61    80    0    208

3                           

0                           

0    62    0    123    61    80    0    208

4                           

0                           

0    62    0    123    61    80    0    208

5                           

0                           

0    62    0    124    61    80    0    207

6                           

0                           

0    62    0    124    61    80    0    207

7                           

0                           

0    62    0    123    61    80    0    208

8                           

0                           

0    62    0    124    61    80    0    207

9                           

0                           

0    62    0    123    61    80    0    208

10                           

0                           

0    62    0    123    61    80    0    208

11                           

0                           

0    62    0    123    61    80    0    208

12                           

0                           

0    62    0    124    61    80    0    207

13                           

0                           

0    62    0    124    61    80    0    207

14                           

0                           

0    62    0    123    61    80    0    208

15                           

0                           

0    62    0    124    61    80    0    207

16                           

0                           

0    62    0    123    61    80    0    208

17                           

0                           

0    62    0    123    61    80    0    208

18                           

0                           

0    62    0    124    61    80    0    207

19                           

0                           

0    62    0    123    61    80    0    208

20                           

0                           

0    62    0    124    61    80    0    207

21                           

0                           

0    62    0    123    61    80    0    208

22                           

0                           

0    62    0    124    61    80    0    207

23                           

0                           

0    62    0    123    61    208    0    80

24                           

0                           

0    62    0    123    61    80    0    208

25                           

0                           

0    62    0    123    61    80    0    208

26                           

0                           

0    62    0    124    61    80    0    207

27                           

0                           

0    62    0    123    61    80    0    208

28                           

0                           

0    62    0    123    61    80    0    208

29                           

0                           

0    62    0    124    61    80    0    207

30                           

0                           

0    62    0    123    61    80    0    208

31                           

0                           

0    62    0    123    61    80    0    208

32                           

0                           

0    62    0    124    61    80    0    207

33                           

0                           

0    62    0    124    61    80    0    207

34                           

0                           

0    62    0    123    61    80    0    208

35                           

0                           

0    62    0    123    61    80    0    208

36                           

0                           

0    62    0    123    61    80    0    208

37                           

0                           

0    62    0    123    61    80    0    208

38                           

0                           

0    62    0    123    61    80    0    208

39                           

0                           

0    62    0    124    61    208    0    79

40                           

0                           

0    62    0    123    61    80    0    208

41                           

0                           

0    62    0    123    61    80    0    208

42                           

0                           

0    62    0    123    61    80    0    208

43                           

0                           

0    62    0    123    61    80    0    208

44                           

0                           

0    62    0    123    61    80    0    208

45                           

0                           

0    62    0    123    61    80    0    208

46                           

0                           

0    62    0    124    61    80    0    207

47                           

0                           

0    62    0    124    61    80    0    207

48                           

0                           

0    62    0    123    61    80    0    208

49                           

0                           

0    62    0    123    61    80    0    208

50                           

0                           

0    62    0    123    61    80    0    208

51                           

0                           

0    62    0    123    61    80    0    208

52                           

0                           

0    62    0    123    61    80    0    208

53                           

0                           

0    62    0    124    61    80    0    207

54                           

0                           

0    62    0    123    61    80    0    208

55                           

0                           

0    62    0    123    61    80    0    208

56                           

0                           

0    62    0    123    61    80    0    208

57                           

0                           

0    62    0    124    61    80    0    207

58                           

0                           

0    62    0    123    61    80    0    208

59                           

0                           

0    62    0    123    61    80    0    208

60                           

0                           

0    62    0    124    61    208    0    79

61                           

0                           

0    62    0    123    61    80    0    208

62                           

0                           

0    62    0    123    61    80    0    208

63                           

0                           

0    62    0    123    61    80    0    208


I let it repeat several times. The only thing that stands out to me is that for ID 23, 39 and 60, bytes 6 and 8 are reversed. Not sure what that means, if anything.
jsimonkeller
Posts: 60
Joined: Sun Oct 30, 2022 2:21 am
Has thanked: 2 times
Been thanked: 5 times

Re: Webasto HVH50

Post by jsimonkeller »

I tested all 3 of my HVH heaters and on all three of them at 19200 baud, at ID 27 (HEX), it finally popped some response when sending a brute force write to all of the IDs using 1,85, 0, 8. FF down the line on all other response ids, but

Heater one returned a 0 at ID 27(HEX)
Heater two returned a 21 (HEX) at ID 27(HEX)
Heater three returned a 28 (HEX) at ID 27(HEX)

Not sure where to go from here.
User avatar
EV_Builder
Posts: 1199
Joined: Tue Apr 28, 2020 3:50 pm
Location: The Netherlands
Has thanked: 16 times
Been thanked: 33 times
Contact:

Re: Webasto HVH50

Post by EV_Builder »

Time to fed it HV , 12Vdc and turn it on?
Converting an Porsche Panamera
see http://www.wdrautomatisering.nl for bespoke BMS modules.
Post Reply