Page 3 of 4
Re: Webasto HVH50
Posted: Fri Feb 09, 2024 3:46 pm
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.
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.

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;
}
Re: Webasto HVH50
Posted: Sat Feb 10, 2024 3:45 pm
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];
Re: Webasto HVH50
Posted: Sat Feb 10, 2024 11:16 pm
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:
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 (23.02 KiB) Viewed 8189 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.
Re: Webasto HVH50
Posted: Sun Feb 11, 2024 5:35 am
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.
Re: Webasto HVH50
Posted: Sun Feb 11, 2024 2:12 pm
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?
Re: Webasto HVH50
Posted: Sun Feb 11, 2024 3:54 pm
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
and the plotter shows this:
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.
Re: Webasto HVH50
Posted: Sat Feb 17, 2024 4:05 am
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?
Re: Webasto HVH50
Posted: Sat Feb 17, 2024 7:33 am
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.
Re: Webasto HVH50
Posted: Sat Feb 17, 2024 4:47 pm
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
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!
Re: Webasto HVH50
Posted: Sat Feb 17, 2024 10:32 pm
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
#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?
Re: Webasto HVH50
Posted: Sat Feb 17, 2024 10:34 pm
by jsimonkeller
Re: Webasto HVH50
Posted: Sun Feb 18, 2024 4:52 pm
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
Re: Webasto HVH50
Posted: Sun Feb 18, 2024 6:14 pm
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?
Re: Webasto HVH50
Posted: Sun Feb 18, 2024 9:32 pm
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.
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.
Re: Webasto HVH50
Posted: Mon Feb 19, 2024 2:03 pm
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!
Re: Webasto HVH50
Posted: Mon Feb 19, 2024 2:37 pm
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.
Re: Webasto HVH50
Posted: Mon Feb 19, 2024 3:37 pm
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!
Re: Webasto HVH50
Posted: Mon Feb 19, 2024 6:06 pm
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)
Re: Webasto HVH50
Posted: Thu Feb 22, 2024 5:28 pm
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.
Updated code for a CRC response and still getting -1
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;
}
Re: Webasto HVH50
Posted: Thu Feb 22, 2024 7:32 pm
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
Re: Webasto HVH50
Posted: Fri Feb 23, 2024 12:37 am
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.
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.
Re: Webasto HVH50
Posted: Sun Feb 25, 2024 7:50 pm
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:
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:
Scope looked like this:
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!
Re: Webasto HVH50
Posted: Sun Feb 25, 2024 11:15 pm
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.
Re: Webasto HVH50
Posted: Tue Feb 27, 2024 4:27 am
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.
Re: Webasto HVH50
Posted: Tue Feb 27, 2024 6:47 am
by EV_Builder
Time to fed it HV , 12Vdc and turn it on?