Building my own digital WBO2-CAN Adapter - help?
#1
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
Because I like to tinker and it doesn't seem all that complicated, and I want smooth closed loop fueling goodness, I've embarked on building my own adapter to take the LC2 digital output and feed it to my MS3 basic over CAN. I am using a Teensy 3.1 micro controller (think arduino on steroids, has a built in CAN controller), and I have a max3232 serial to UART bridge. However I cannot seem to read any messages coming from the LC2 on the Teensy, through the max3232. Does anyone know if it follows normal RS232 protocol? I can read LC2 messages on my laptop in realterm, and I can send messages at the same baud rate to my teensy from realterm. But I can't read messages on the teensy from the LC2.
In summary, this works:
realterm (set to 19200,8n1) --> usb/rs232 adapter -> max3232 -> teensy --> serial monitor
and this works:
serial monitor --> teensy --> max3232 --> usb/rs232 adapter --> realterm (set to 19200, 8n1)
and this works:
wideband lc2 --> usb/rs232 adapter -> realterm (set to 19200, 8n1)
but this doesn't:
wideband lc2 --> max3232 --> teensy --> serial monitor
I'm not getting any messages whatsoever on the Teensy, not even some garbled mess suggesting that it's a translation issue. The only thing I can think of is that the LC2 doesn't actually use RS232. But I don't have a scope to check the TX voltage (I don't want to fry my microcontroller)
Hoping someone who's embarked on something similar can shed some light. Thanks!
In summary, this works:
realterm (set to 19200,8n1) --> usb/rs232 adapter -> max3232 -> teensy --> serial monitor
and this works:
serial monitor --> teensy --> max3232 --> usb/rs232 adapter --> realterm (set to 19200, 8n1)
and this works:
wideband lc2 --> usb/rs232 adapter -> realterm (set to 19200, 8n1)
but this doesn't:
wideband lc2 --> max3232 --> teensy --> serial monitor
I'm not getting any messages whatsoever on the Teensy, not even some garbled mess suggesting that it's a translation issue. The only thing I can think of is that the LC2 doesn't actually use RS232. But I don't have a scope to check the TX voltage (I don't want to fry my microcontroller)
Hoping someone who's embarked on something similar can shed some light. Thanks!
#2
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
Code is simple. Read from one, send to other. Serial is the serial monitor on my laptop. Serial1 is wired into the MAX3232.
Code:
#define HWSERIAL Serial1 void setup() { Serial.begin(9600); HWSERIAL.begin(19200, SERIAL_8N1); } void loop() { int incomingByte; if (Serial.available() > 0) { incomingByte = Serial.read(); Serial.print("USB received: "); Serial.println(incomingByte, DEC); //HWSERIAL.print("USB received:"); //HWSERIAL.println(incomingByte, DEC); } if (HWSERIAL.available() > 0) { incomingByte = HWSERIAL.read(); Serial.print("UART received: "); Serial.println(incomingByte, DEC); //HWSERIAL.print("UART received:"); //HWSERIAL.println(incomingByte, DEC); } }
#3
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
I've attempted doing my own LC2 display using serial communication with the intent of eventually output the data to the MS3 via CANbus. I was able to read the LC2 serial data into an Arduino. However, I was not able to decipher the data. It did not seem to match their documentation at all. I eventually just gave up.
There was another thread of someone else working on a similar project but I can't find it at the moment.
There was another thread of someone else working on a similar project but I can't find it at the moment.
#4
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
I've attempted doing my own LC2 display using serial communication with the intent of eventually output the data to the MS3 via CANbus. I was able to read the LC2 serial data into an Arduino. However, I was not able to decipher the data. It did not seem to match their documentation at all. I eventually just gave up.
There was another thread of someone else working on a similar project but I can't find it at the moment.
There was another thread of someone else working on a similar project but I can't find it at the moment.
#6
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
I'd appreciate that. Like I said, I could just plug it into my Teensy but if I'm wrong and the lc2 is spitting out over 5v then it's toast.
#8
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
Got it working. It looks like the male to male db9 connector I used was not properly mapping the pins out to the other side. Hooking them up manually got me going. Successfully reading AFR values, as well as the LC-2 status (warming up, errors, etc).
So for the record, it is RS232 and you can read it with a MAX3232. Next step is hooking up the CAN side and trying to read/send messages. Woop.
So for the record, it is RS232 and you can read it with a MAX3232. Next step is hooking up the CAN side and trying to read/send messages. Woop.
#9
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
I got it working - my male to male serial adapter was screwing things up. Connected the TX and gnd db9 pins directly and now it's good. And the code that I found/modified to interpret the lc1 packets works as well - reads the status packet accurately and shows the afr. Next step is to get it CAN communications going.
#10
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
these snippets might help.. fair warning, I haven't touched this code in a little over 2 years.
Code:
void LC1::get_AFR() { byte incoming_byte; byte index; byte LC1_status; byte LC1_AFR; byte LC1_AFRs; int LC1_lambda; byte packet[8]; while (Serial3.available() > 0){ incoming_byte=Serial3.read(); if ( (incoming_byte & 0xA2) == 0xA2 ) { // synchronization byte index=0; packet[0]=incoming_byte; } else if ((index == 0) && ((incoming_byte & 0x80) == 0x80)) { // 2nd syncro byte index=1; packet[1]=incoming_byte; } else { index++; packet[index]=incoming_byte; } if (index >= 5 ) { LC1_status = (packet[2] & B00011100) >> 2; LC1_AFRs = (packet[2] & B00000001) << 7; LC1_AFRs += packet[3] & B01111111; LC1_lambda = packet[4] & B00111111; LC1_lambda = LC1_lambda << 7; LC1_lambda += (packet[5] & B01111111); switch (LC1_status) { case 0: LC1_AFR = LC1_lambda; break; // reporting lambda case 1: LC1_AFR = ((LC1_lambda + 500) * LC1_AFRs ) / 1000; break; case 2: Serial.println("Free Air Calibration in progress..."); break; case 3: Serial.println("Need Calibration"); break; case 4: Serial.println("Heater Warming"); break; case 5: Serial.println("Heater Calibration"); break; case 6: Serial.println("Error Code"); break; case 7: Serial.println("Reserved"); break; } if (LC1_status == 0 ) { Serial.print("lambda "); Serial.println(LC1_lambda); Serial.print("AFR "); Serial.println(LC1_AFR); index=0; for (byte i; i <=6 ; i++) packet[i]=0; } }// end index_5 }//end while }// end lc1_read
Code:
void MSRequest(byte block, unsigned int offset, byte req_bytes) { #define CAN_ID 3 #define MEGASQUIRT_ID 0 byte databuffer[8]; enum msg_type { MSG_CMD, MSG_REQ, MSG_RSP, MSG_XSUB, MSG_BURN }; databuffer[0]=block; databuffer[1]=offset >> 3; databuffer[2]=(((offset & B00000111) << 5 ) | req_bytes); MS_tx_packet(offset, MSG_REQ, CAN_ID, MEGASQUIRT_ID, block, 3, databuffer); } void MS_tx_packet(unsigned int var_offset, byte msg_type, byte from_id, byte to_id, byte var_block, byte dlc, byte data[8]) { //Spare bits unused byte IDR0, IDR1, IDR2, IDR3; /* Megasquirt CANBus Format -> FlexCan decoder . 76543210 . IDR0 - ___ooooo - 3 bits blank, offset . IDR1 - oooooomm - offset, msg_type . IDR2 - mffffttt - msg_type, from_id, to_id . IDR3 - tbbbbBss - to_id, block, spare . Flexcan msg.id . | IDR0 | IDR1 | IDR2 | IDR3 | . can.id - 0001 1111 1111 1111 1111 1111 1111 1111 . overlay - ___o oooo oooo oomm mfff fttt tbbb bBss */ // Cut n Paste bits into bytes // ___ooooo - first 3 bits truncated in the can.id long IDR0 = lowByte((var_offset >> 6)); // shift right, then paste // oooooomm - offset, msg_type IDR1 = (lowByte(var_offset) & B00111111) << 2; IDR1 += ((msg_type & B00000110) >> 1); // mffffttt - msg_type, from_id, to_id IDR2 = ((msg_type & B00000001) << 7); IDR2 += (from_id & B00001111) << 3; IDR2 += (to_id & B00001110) >> 1; // tbbbbBss - to_id, block, spare IDR3 = (to_id & B00000001) << 7; IDR3 += (var_block & B00001111) << 3; IDR3 += (var_block & B00010000) >> 2; msg.id=0; // clear data // assemble bytes into uint32 for msg.id msg.id += IDR0 << 24; msg.id += IDR1 << 16; msg.id += IDR2 << 8; msg.id += IDR3; msg.ext = 1; // extended ID set msg.len = dlc; for ( byte idx=0; idx<8; ++idx ) { msg.buf[idx] = data[idx]; } #ifdef DEBUG Serial.print("var_offset: "); Serial.println(var_offset); Serial.print("msg_type: "); Serial.println(msg_type); Serial.print("from_id: "); Serial.println(from_id); Serial.print("to_id: "); Serial.println(to_id); Serial.print("var_block: "); Serial.println(var_block); Serial.print("dlc: "); Serial.println(dlc); Serial.println("msg.id: "); Serial.println(msg.id, HEX); #endif CANbus.write(msg); }
#11
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
these snippets might help.. fair warning, I haven't touched this code in a little over 2 years.
Code:
void LC1::get_AFR() { byte incoming_byte; byte index; byte LC1_status; byte LC1_AFR; byte LC1_AFRs; int LC1_lambda; byte packet[8]; while (Serial3.available() > 0){ incoming_byte=Serial3.read(); if ( (incoming_byte & 0xA2) == 0xA2 ) { // synchronization byte index=0; packet[0]=incoming_byte; } else if ((index == 0) && ((incoming_byte & 0x80) == 0x80)) { // 2nd syncro byte index=1; packet[1]=incoming_byte; } else { index++; packet[index]=incoming_byte; } if (index >= 5 ) { LC1_status = (packet[2] & B00011100) >> 2; LC1_AFRs = (packet[2] & B00000001) << 7; LC1_AFRs += packet[3] & B01111111; LC1_lambda = packet[4] & B00111111; LC1_lambda = LC1_lambda << 7; LC1_lambda += (packet[5] & B01111111); switch (LC1_status) { case 0: LC1_AFR = LC1_lambda; break; // reporting lambda case 1: LC1_AFR = ((LC1_lambda + 500) * LC1_AFRs ) / 1000; break; case 2: Serial.println("Free Air Calibration in progress..."); break; case 3: Serial.println("Need Calibration"); break; case 4: Serial.println("Heater Warming"); break; case 5: Serial.println("Heater Calibration"); break; case 6: Serial.println("Error Code"); break; case 7: Serial.println("Reserved"); break; } if (LC1_status == 0 ) { Serial.print("lambda "); Serial.println(LC1_lambda); Serial.print("AFR "); Serial.println(LC1_AFR); index=0; for (byte i; i <=6 ; i++) packet=0; } }// end index_5 }//end while }// end lc1_read
Code:
void MSRequest(byte block, unsigned int offset, byte req_bytes) { #define CAN_ID 3 #define MEGASQUIRT_ID 0 byte databuffer[8]; enum msg_type { MSG_CMD, MSG_REQ, MSG_RSP, MSG_XSUB, MSG_BURN }; databuffer[0]=block; databuffer[1]=offset >> 3; databuffer[2]=(((offset & B00000111) << 5 ) | req_bytes); MS_tx_packet(offset, MSG_REQ, CAN_ID, MEGASQUIRT_ID, block, 3, databuffer); } void MS_tx_packet(unsigned int var_offset, byte msg_type, byte from_id, byte to_id, byte var_block, byte dlc, byte data[8]) { //Spare bits unused byte IDR0, IDR1, IDR2, IDR3; /* Megasquirt CANBus Format -> FlexCan decoder . 76543210 . IDR0 - ___ooooo - 3 bits blank, offset . IDR1 - oooooomm - offset, msg_type . IDR2 - mffffttt - msg_type, from_id, to_id . IDR3 - tbbbbBss - to_id, block, spare . Flexcan msg.id . | IDR0 | IDR1 | IDR2 | IDR3 | . can.id - 0001 1111 1111 1111 1111 1111 1111 1111 . overlay - ___o oooo oooo oomm mfff fttt tbbb bBss */ // Cut n Paste bits into bytes // ___ooooo - first 3 bits truncated in the can.id long IDR0 = lowByte((var_offset >> 6)); // shift right, then paste // oooooomm - offset, msg_type IDR1 = (lowByte(var_offset) & B00111111) << 2; IDR1 += ((msg_type & B00000110) >> 1); // mffffttt - msg_type, from_id, to_id IDR2 = ((msg_type & B00000001) << 7); IDR2 += (from_id & B00001111) << 3; IDR2 += (to_id & B00001110) >> 1; // tbbbbBss - to_id, block, spare IDR3 = (to_id & B00000001) << 7; IDR3 += (var_block & B00001111) << 3; IDR3 += (var_block & B00010000) >> 2; msg.id=0; // clear data // assemble bytes into uint32 for msg.id msg.id += IDR0 << 24; msg.id += IDR1 << 16; msg.id += IDR2 << 8; msg.id += IDR3; msg.ext = 1; // extended ID set msg.len = dlc; for ( byte idx=0; idx<8; ++idx ) { msg.buf[idx] = data[idx]; } #ifdef DEBUG Serial.print("var_offset: "); Serial.println(var_offset); Serial.print("msg_type: "); Serial.println(msg_type); Serial.print("from_id: "); Serial.println(from_id); Serial.print("to_id: "); Serial.println(to_id); Serial.print("var_block: "); Serial.println(var_block); Serial.print("dlc: "); Serial.println(dlc); Serial.println("msg.id: "); Serial.println(msg.id, HEX); #endif CANbus.write(msg); }
I still need to figure out why the EGO request packets from my megasquirt are reporting 597 and 605 for myvaroffset.
#12
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
MS's request code is kinda stupid (at least it was 2 years ago). It spams the bus. You can write directly to the block
ffset if you can find it in the .ini. Values are persistent until overwritten - so you don't have to write the AFR every millisecond, just whenever a new LC1 packet arrives. This is where LC1's averaging/instant settings become interesting.
![embarassed](https://www.miataturbo.net/images/smilies/redface.gif)
#13
Junior Member
Thread Starter
Join Date: Jul 2009
Location: Orange County, CA
Posts: 419
Total Cats: 45
![Default](https://www.miataturbo.net/images/icons/icon1.gif)
MS's request code is kinda stupid (at least it was 2 years ago). It spams the bus. You can write directly to the block
ffset if you can find it in the .ini. Values are persistent until overwritten - so you don't have to write the AFR every millisecond, just whenever a new LC1 packet arrives. This is where LC1's averaging/instant settings become interesting.
![embarassed](https://www.miataturbo.net/images/smilies/redface.gif)
I also got the 29bit request/response working to display data on a gauge of some sort. Now to work on the hardware part (which I'm not as good at).
Last edited by Morello; 06-29-2016 at 02:16 PM.