Generating serial line break for LIN-bus

Status
Not open for further replies.

skpang

Well-known member
I'm trying to write a LIN-bus driver for Teensy 3.2

A LIN-bus frame consist of break, synch(0x55), Ident, data. I'm trying to do this in software and found when I configure the uart there seems to be a delay of 1mS before the synch(0x55) is sent out.

Code:
int led = 13;
int lin_cs = 23;
int tx_pin = 1;
int test_pin = 5;

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

  digitalWrite(test_pin, HIGH);
  pinMode(tx_pin, OUTPUT);    
  digitalWrite(tx_pin, HIGH); 
  delay(100);
   
  
  digitalWrite(tx_pin, LOW);  // Break
  delayMicroseconds(1024);    // Break dealy
  digitalWrite(tx_pin, HIGH); 
  
  digitalWrite(test_pin, LOW); 
  Serial1.begin(9600);
  digitalWrite(test_pin, HIGH); 
  
  Serial1.write(0x55); // Synch
  
  Serial1.write(0x23); // Ident
  Serial1.write(0x41);  // Data
}

void loop() {

  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(500); 
  digitalWrite(led, HIGH);
  delay(100); 
}
scope_11.png

Any idea why there is a delay of 1mS before the synch byte is sent out and how to remove that ?

The green trace is the test_pin to show where is the code is.

I also tried this on an Uno board there is no delay before the synch byte is sent out.
 
did you try a putting few ms delay after serial1.begin() before sending the byte? or perhaps try a pullup/pulldown on the TX pin when reconfiguring the peripheral for serial mode?

you could also try setting serial mode first, then changing the core pin manually via registers, write it, then switch it back? :)
 
did you try a putting few ms delay after serial1.begin() before sending the byte? or perhaps try a pullup/pulldown on the TX pin when reconfiguring the peripheral for serial mode?

you could also try setting serial mode first, then changing the core pin manually via registers, write it, then switch it back? :)
I don't want any delay before the synch byte (0x55).
I might try and set it serial mode first. Change the pin, output the break then switch it back like you said but this might not make it portable across T3.2 and T3.6 but I will give it a go.

I think it might be something to do with the buffer/FIFO/interrupt. When I use Serial1.write(0x55) then Serial1.write(0x23), I can't see the output straight away. Maybe it is queued. I did tried and changed the serial1.c interrupt priority from 64 to 32 but it didn't make any difference.

Code:
int led = 13;
int lin_cs = 23;
int tx_pin = 1;
int test_pin = 5;

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

  digitalWrite(test_pin, HIGH);
  pinMode(tx_pin, OUTPUT);    
  digitalWrite(tx_pin, HIGH); 
  delay(10);
   
  
  digitalWrite(tx_pin, LOW);  // Break low
  delayMicroseconds(1024);    // Break delay
  digitalWrite(tx_pin, HIGH); // Break high

  Serial1.begin(9600);        // Configure serial
 
  digitalWrite(test_pin, LOW);  // Green trace on scope
  digitalWrite(test_pin, HIGH); 
  
  Serial1.write(0x55); // Synch
  
  delayMicroseconds(40);        // Delay to let it show up on scope
  digitalWrite(test_pin, LOW);   // Green trace on scope
  digitalWrite(test_pin, HIGH);
  
  Serial1.write(0x23); // Ident
  Serial1.write(0x41);  // Data
}

void loop() {

  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(500); 
  digitalWrite(led, HIGH);
  delay(100); 
}
scope_14.png
 
I can't set the Serial1.begin(9600) in advance because I need to set the tx pin low to sent out the break. Unless I manually set the tx pin low via registers but I don't really want to mess about with registers.

Just tried the Serial.send_now() but it didn't make any difference.

Code:
Serial1.begin(9600);        // Configure serial
  Serial.send_now();
  
  digitalWrite(test_pin, LOW);
  digitalWrite(test_pin, HIGH); 
  
  Serial1.write(0x55); // Synch
  Serial.send_now();
 
  delayMicroseconds(40);        // Delay to let it show up on scope
  digitalWrite(test_pin, LOW); 
  digitalWrite(test_pin, HIGH);
 
  Serial1.write(0x23); // Ident
  Serial.send_now();
  Serial1.write(0x41);  // Data

I think Serial.send_now() might be just for the USB serial but I'm using Serial1.

Tried Serial1.send_now() but it won't compile with an error of "'class HardwareSerial' has no member named 'send_now'".
 
Opps - that was an easy test/fail.

What happens if you call this after .begin()? :: void serial_set_transmit_pin(uint8_t pin) [from: ...\cores\teensy3\serial1.c]

It does a set output, writes low, then sets for Serial usage - may be too fast of a low assuming it then goes high.

Maybe in combination with what is posted it will restore the pin without a full .begin() call?
 
I think it is working now.

After the Serial1.begin(9600) I sent out the break then reconfigure using serial_set_transmit_pin(tx_pin) but I have to add serial_set_tx(tx_pin,1).

Code:
int led = 13;
int lin_cs = 23;
int tx_pin = 1;
int test_pin = 5;

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

  digitalWrite(test_pin, HIGH);
  pinMode(tx_pin, OUTPUT);    
  digitalWrite(tx_pin, HIGH); 
  delay(10);
   
  
 // digitalWrite(tx_pin, LOW);  // Break low
 // delayMicroseconds(1024);    // Break delay
 // digitalWrite(tx_pin, HIGH); // Break high

  Serial1.begin(9600);        // Configure serial

  pinMode(tx_pin, OUTPUT);  
  digitalWrite(tx_pin, LOW);  // Break low
  delayMicroseconds(1024);    // Break delay
  digitalWrite(tx_pin, HIGH); // Break high

  serial_set_transmit_pin(tx_pin);
  serial_set_tx(tx_pin,1);
 
  digitalWrite(test_pin, LOW);
  digitalWrite(test_pin, HIGH); 
  
  Serial1.write(0x55); // Synch

  delayMicroseconds(40);        // Delay to let it show up on scope
  digitalWrite(test_pin, LOW); 
  digitalWrite(test_pin, HIGH);
 
  Serial1.write(0x23); // Ident
  Serial1.write(0x41);  // Data
  
}

void loop() {

  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(500); 
  digitalWrite(led, HIGH);
  delay(100); 
}

scope_15.png

Thanks for everyone's help.
 
for the most part 3.2/3.5/3.6 most if not all of the commands/registers are the same, so portability for most part should be okay :) if you are writing a library for LIN bus using uart maybe you can add LC support as well as some people do use them
 
Status
Not open for further replies.
Back
Top