Any experience with AVR LIN/UART hardware?

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do not have any ATmega CAN chips with their LIN/UART hardware handy to develop this code right now. All I did was read the data sheet trying to pick out UART only operation mode without LIN operation. I have no idea if I got it right/wrong or maybe did not even get close to a working solution. This is simple polling based throwaway UART debug code to output serial data characters for AT90CAN or ATmega CAN chip programming examples. I decided to make it work on either type of CAN chip by detecting the type of processor when compiling the C code, but I have no idea if the LIN/UART debug code will really work or not (the AT90CAN USART code works).

// WinAVR C code:
// This code emulates the AT90CAN USART sample rates of 16 (U2X_SINGLE) and 8 (U2X_DOUBLE) in
// the ATmega CAN chips LIN/UART hardware. This is done because it is part of a conditional
// compile that chooses between the AT90CAN chips or ATmega CAN chips. Using the same sample
// rates means the same UART baud rate formulas work for all these CAN chips.

#include 

//#define F_CPU 16000000UL

#define U2X_SINGLE      0
#define U2X_DOUBLE      1

#define USART0_BAUDRATE         57600UL
#define USART0_SPEED            U2X_DOUBLE

#define BAUD_PRESCALE ((((F_CPU + (USART0_BAUDRATE * 8UL)) / (USART0_BAUDRATE * 16UL))) - 1)
#define BAUD_2X_PRESCALE ((((F_CPU + (USART0_BAUDRATE * 4UL)) / (USART0_BAUDRATE * 8UL))) - 1)

//*******************************************************
// LIN/UART hardware setup for Tx output only, 8 bits, no parity and one stop bit.
//
void usart0_init () {
    LINCR = (1 << LSWRES);                  // Ensure LENA is cleared so LDISR/LBT may be written.

  #if (USART0_SPEED == U2X_SINGLE)
    LINBRRH = (uint8_t) (BAUD_PRESCALE >> 8);
    LINBRRL = (uint8_t) BAUD_PRESCALE;
  #elif (USART0_SPEED == U2X_DOUBLE)
    LINBRRH = (uint8_t) (BAUD_2X_PRESCALE >> 8);
    LINBRRL = (uint8_t) BAUD_2X_PRESCALE;
  #endif

  #if (USART0_SPEED == U2X_SINGLE)
    LINBTR = (1 << LDISR) | (16 << LBT0);   // Set sample rate to 16 (same as AT90CAN U2X_SINGLE).
  #elif (USART0_SPEED == U2X_DOUBLE)
    LINBTR = (1 << LDISR) | (8 << LBT0);    // Set sample rate to 8 (same as AT90CAN U2X_DOUBLE).
  #endif

        // Enable the LIN/UART, set UART Tx byte enable, mode 00 - 8 bit no parity.
    LINCR = (1 << LENA) | (1 << LCMD2) | (1 << LCMD0);    
}

//*******************************************************
// A primitive polling routine to send the byte_data on the USART0 Tx.
// ATmega CAN chip LIN/UART driver for UART mode Tx:
//
void raw_usart0_tx (unsigned char byte_data) {
    while (LINSIR & (1 << LBUSY));          // Wait while the UART is busy.
    LINDAT = byte_data;                     // Tx the raw byte value.
}

I think I got the UART baud rate correct, but I'm not sure if this is the correct way to setup and control the LIN/UART character output UART only Tx. Any input help from someone with experience using the 8 bit AVR LIN/UART hardware would be appreciated.

It would have been nice if ATMEL had an app note on using only the UART of the LIN/UART hardware.

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made a LIN controller using a regular old AVR uart and a Melexis TH8062 LIN chip.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bob, thank you for the response.

The trouble is I do not want to use LIN, I just want to have a simple Tx only UART instead.

The data sheet only mentions using the LINSIR register LTXOK Transmit Performed Interrupt bit to detect the end of a UART Tx operation (when in UART mode and not LIN mode). I assumed (hope) it is possible to use the LINSIR register LBUSY Busy Signal for polling when the Tx completes and ignore the LTXOK bit since this interrupt is disabled (LINENIR.LENTXOK=0). I think LBUSY will work because the entire LIN/UART is only used for UART Tx, so there will not be any confusion between a Rx or Tx busy when there is never any Rx.

There is also some complexity in the LIN/UART register setup where certain register bits are only available when other register bits are in a specific state. Since the data sheet UART description made no mention of these specific bit states, I had to extract this information from the LIN description. This is not optimal and leaves room for misunderstandings on my part that could lead to broken code.

I have an AT90CAN Controller Area Network (CAN) example program that uses primitive polled USART output to show it is working correctly. Since the CAN hardware in the ATmega CAN chips is so similar I decided to expand this single example program to compile for all the AVR 8 bit CAN chips.

Since I do not have this LIN/UART hardware on hand and I have no direct experience with this hardware, I cannot confirm if any of this code works or not. I was hoping that someone with LIN/UART experience could tell me if I messed up or not.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you just want to use the LIN hardware for regular USART:

#elif IS_TINY(167)
#define UCR             LINENIR
#define USR             LINSIR
#define UDR             LINDAT
#define RXC             LRXOK
#define UDRE            LTXOK
#define SETBAUD(baud)   {LINBRRL = ((SYSCLK/1600)/(baud/100)) - 1;LINBTR=(1<<LDISR)|16;} 
#define SETCTL()        LINCR = (1<<LENA)|(7<<LCMD0)
#define TXBUSY()        ((LINSIR & (1<<LBUSY)) != 0)
#define RXVECNM         LIN_TC
#define RXCIE           LENRXOK
...
#define KBHIT           ((USR & (1<<RXC)) != 0)
#define RDUDR(var)      {var = UDR;}
#ifndef TXBUSY
#define TXBUSY()        ((USR & (1<<UDRE)) == 0)
#endif
#define TXCLR()
#define TXUDR(var)      {UDR = var;}

These macros work ok with a Tiny167 in polled mode. I can't remember whether I have used them with RX (or TX) interrupts.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David, thank you for the response.

From the data sheet:

• Bit 4 - LBUSY: Busy Signal
    – 0 = Not busy,
    – 1 = Busy (receiving or transmitting).

This appears to contradict the TXBUSY label of this macro when Tx and Rx are both used.

#define TXBUSY()        ((LINSIR & (1<<LBUSY)) != 0)

This contradiction does not appear to be a big problem. I assume full duplex UART Tx might take a little longer depending on Rx activity, but it should still work. Your macros do tell me important things like setting both LDISR and LBT bits in the same write works (I was not sure since LDISR=1 was a condition required to access the LBT bits). I think I will chance leaving my code as is with an "untested code" warning. Worth every penny paid for a free example program :wink:! Even if I got something wrong it is only a minor utility function that should be easy to fix. Still your reply gives me some confidence it has a good chance of working 8).

Thanks for the macros. In the future having macros to emulate a standard AVR hardware USART interface is a good way to reuse older AVR code with the LIN/UART hardware. This is overkill for my current needs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can dig out the Tiny167 and test the interrupts if you want.

Using macros makes adding a MCU simple. After all, most USARTs have similar operations. The same "serial.c" source file handles AVR, 8051, PIC, STM8S, ARM7, 740, ... and multiple compilers.

Several ARM chips will do LIN. AFIK the only AVR is ATtiny167.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, I've got my solution without using interrupts. My example code runs an event timer that produces a slow human readable serial data output UART message rate by slowing the CAN traffic completed message rate, so there is no penalty for polling delays in the UART operation.

My example program is a CAN driver for the AT90CANxxx family AVRs. As an afterthought I decided to add support for the ATmega CAN chips to the source code. Except I do not have any ATmega CAN chips on hand to test with making it more difficult to deal with LIN/UART hardware that I have never used before.

david.prentice wrote:
Several ARM chips will do LIN. AFIK the only AVR is ATtiny167.
There are some other AVRs. The ATmega16M1, ATmega32M1, ATmega64M1, ATmega32C1 and ATmega64C1 automotive Controller Area Network (CAN) chips have the same LIN/UART hardware as the ATtiny167. There is also the ATtiny87 (an 8k version of the ATtiny167).

ATMEL also has an application note with source code for doing LIN without the LIN/UART hardware:
AVR322: LIN Protocol Implementation on megaAVR Microcontrollers
This uses the standard USART or USI hardware for LIN.

I like the LIN/UART programmable sample rate. Since CAN requires an exact external AVR clock speed for generating its baud, this prevents picking an AVR clock speed that is friendly for UART standard baud rates. The LIN/UART programmable sample rate fixes this problem.

ATmega CAN data sheet wrote:
The UART has an enhanced baud rate generator providing a maximum error of 2 percent whatever the clock frequency and the targeted baud rate.
Thank you again for the help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi ..i am the user from the CAN bus, today i have wrote a simple script for UART with atmega64C1 and i am 99% thats working. On my Pc was everything ok!! Here is the code

/*
 * main.c
 *
 *  Created on: Jan 18, 2013
 *      Author: tosis
 */


/* -----------------------------------------------------------------------
 * Title:    Configuration USART Rx (8 bit + 1 stop bit 34800)
 * Hardware: ATmega68C1
 * Software: Eclipse
 -----------------------------------------------------------------------*/

#define F_CPU 16000000UL                  // Clock frequency
#include 
#include 
#include 
#include 


#define BAUD 38400                        // Baud rate


// ********************************* Initialisation USART *********************************

unsigned char String[] = "Hello word!!!";

void USART_Init( void)
{
LINCR = (1 << LSWRES);
LINBRRH = (((F_CPU/BAUD)/16)-1)>>8;
LINBRRL = (((F_CPU/BAUD)/16)-1);

LINCR = (1<<LENA)|(1<<LCMD2)|(1<<LCMD1)|(1<<LCMD0);
}


 //* ************************************* USART ATMEGA64C1 Tx**********************************
 int at64c1_transmit (unsigned char byte_data) {
    while (LINSIR & (1 << LBUSY));          // Wait while the UART is busy.
    LINDAT = byte_data;
    return 0;
}



// ************************************* MAIN LOOP **************************************

int main( void )
{

USART_Init ();                    // initialisation


volatile int x;

    for(;;)                               // super loop
    {

        for (x = 0 ; x < 13 ; x++)
        {

        at64c1_transmit(String[x]);                   // Send characters
        }


        at64c1_transmit(13);                          // Enter

    }

return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for posting the code.

One thing in your code does not make sense because the default for the LINBTR.LBTn bits is 32 decimal. This should make your baud rate formula:

LINBRRH = (((F_CPU/BAUD)/32)-1)>>8;
LINBRRL = (((F_CPU/BAUD)/32)-1);

I think (I still do not have the actual chip to try out) you need to change the LINBTR register LBT5 through LBT0 bits from the 32 default value to a value of 16 decimal.

LINBTR = (1 << LDISR) | (16 << LBT0);

in order to use your current baud formula:

LINBRRH = (((F_CPU/BAUD)/16)-1)>>8;
LINBRRL = (((F_CPU/BAUD)/16)-1);

Your baud rate formula might be off by one for some baud rates because the integer result does not round up. For example a LINBRR value of 17.9, almost 18 would truncate to a 17 integer result. With round up the 17.9 value would become an integer value of 18. This lack of round up will maximize the percentage of baud rate error for some baud rates.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi...i have made the suggested changes in the code, i can tell that its working again. The difference between the two examples is that:
With the old one code i have the message Hello Word!!! on my screen very quickly, really very fast, like a bullet. With the second code, with the changes in LINBTR i hve the message on the screen, like some one to type this, i am not sure if the esplain is good, but i can see for example this...
Hello after some time i have Hello W after Hello Wo...etc, its like someont to type this slowly on keyboard!! Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I added extra this code

int at64c1_receive (void) {
     while (LINSIR & (1 << LBUSY));          // Wait while the UART is busy.

     return LINDAT;
 }
 FILE uart_stlib = FDEV_SETUP_STREAM(at64c1_transmit,at64c1_receive,_FDEV_SETUP_RW); 

a function to receive and a connect with the stdlib from C, and needed this code in main function

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
stdout = stdin = &uart_stlib; 

and can some one use the printf to print something like this

SORRY i cannot post the printf function, i have an error from forum, from server!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Most likely it is this:

https://www.avrfreaks.net/index.p...
Tip #2 : Get a percent sign into a post

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok thank you very much, this is all the code in one post!!

/*
 * main.c
 *
 *  Created on: Jan 18, 2013
 *      Author: tosis
 */


/* -----------------------------------------------------------------------
 * Title:    Configuration USART Rx (8 bit + 1 stop bit 34800)
 * Hardware: ATmega68C1
 * Software: Eclipse
 -----------------------------------------------------------------------*/

#define F_CPU 16000000UL                  // Clock frequency
//Includes ...Maybe you need to change this path!!! 
#include 
#include 
#include 
#include 
#include 


#define BAUD 38400                        // Baud rate


// ********************************* Initialisation USART *********************************

unsigned char String[] = "Hello world!!!";

void USART_Init( void)
{
LINCR = (1 << LSWRES);
LINBRRH = (((F_CPU/BAUD)/16)-1)>>8;
LINBRRL = (((F_CPU/BAUD)/16)-1);
LINBTR = (1 << LDISR) | (16 << LBT0);
LINCR = (1<<LENA)|(1<<LCMD2)|(1<<LCMD1)|(1<<LCMD0);
}


 //* ************************************* USART ATMEGA64C1 Tx**********************************
 int at64c1_transmit (unsigned char byte_data) {
    while (LINSIR & (1 << LBUSY));          // Wait while the UART is busy.
    LINDAT = byte_data;
    return 0;
}
 int at64c1_receive (void) {
     while (LINSIR & (1 << LBUSY));          // Wait while the UART is busy.

     return LINDAT;
 }
 FILE uart_str = FDEV_SETUP_STREAM(at64c1_transmit,at64c1_receive,_FDEV_SETUP_RW);

// ************************************* MAIN LOOP **************************************

int main( void )
{
stdout = stdin = &uart_str;
USART_Init ();                    // initialisation
int turn=5;

volatile int x;

    for(;;)                               // super loop
    {

/*        for (x = 0 ; x < 13 ; x++)   //If you uncomment this section you can see te message Hello World
        {

        at64c1_transmit(String[x]);                   // Send characters
        }


        at64c1_transmit(13);      */                    // Enter
        printf("Tje number is %d, Atmega64C1!!\n\n",turn);
        _delay_ms(500);
    }

return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi...i have seen the libraries from Atmel for Lin protocol and there are and an example with a master and salve node. I have a question, i found Lin protocol more simple i understand how works.
There are this code

ISR(TIMER0_COMPA_vect) {

    rtc_tics++;                                                                                                    
                                                                                                                   
    if((rtc_tics & 0x01) == 0x01) {                                                                                
        lin_tx_header((unsigned char)LIN_2X, (unsigned char)LIN_ID_0, 0);                                  
    } else {                                                                                                       
        lin_tx_header((unsigned char)LIN_2X, (unsigned char)LIN_ID_1, 0);
    }                                   
}                 

And i want to ask why the Master node send an id and the same time the Master node read the own message to response? Is that the only way for the Lin bus or this is only an example?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ntosis wrote:
And i want to ask why the Master node send an id and the same time the Master node read the own message to response? Is that the only way for the Lin bus or this is only an example?
From: AVR308: Software LIN Slave
http://www.atmel.com/Images/doc1...
Quote:
The LIN protocol does not define an acknowledgment procedure for the Slave tasks. The Master task uses its own slave task to verify that the sent message frame is identical with the one received by this slave task. If any discrepancy is detected the message frame can be retransmitted.
Fault tolerance was added to the later LIN specifications.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, thank you... i need some informations about LIN , i understand how works the code and i have thin function for 2 nodes, Master and Slave!!

void lin_id_task (void) {
                                                                                                      
    switch (Lin_get_id()) {     //Macros in lin_drv.h                                                                                   
        case LIN_ID_0:                                                                                     
            lin_tx_response(LIN_2X, lin_motor_command, LEN_0);                                     
            break;                                                                                 
        case LIN_ID_1:                                                                                     
            lin_rx_response(LIN_2X, LEN_1);                                                        
            break;                                                                                 
        default:                                                                                           
            // ID: absent/refused                                                                  
            break;                                                                                 
    }                                                                                                              
}

The Master sends a Header every 10 ms with an interrupt, when the ID is the same with ID_0 for example 0x12 then the master node execute the function lin_tx_response(); and the slave node the function lin_rx_responce(). If i have 2 or more slaves how can i change the code? Need i two ID for every slave?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since this subject is about using hardware, you should start a new forum thread about the LIN protocol. People that could read and respond to a LIN protocol question will likely ignore this thread and never read it.

This has some LIN information:
https://en.wikipedia.org/wiki/Lo...

It appears you may request a copy of the actual LIN specification on the web:
http://www.lin-subbus.org/
Check out the Specification section Document Request.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

https://www.avrfreaks.net/index.p...

ok, thanx i have made a thread on this Link

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 FILE uart_str = FDEV_SETUP_STREAM(at64c1_transmit,at64c1_receive,_FDEV_SETUP_RW);

the upper line occurs error " '[' expected " when building on codevision.

Please tell me about the reason.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wrong compiler. Example uses AtmelStudioGCC specific include files

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi

 

I'm struggled with lin implimentation for the atsame70q21 micro controller.i 'm develop code for lin using usart driver there is no issues in compilation but the registers are not reading the values.i'm checked my hardware and software no issues i did'nt found.i dont know what i'm doing.any one help me please.

 

Thanks

 

 

rajeswari

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rajeswari Pallagani wrote:
.i dont know what i'm doing.any one help me please.

https://opensource.com/life/16/1...

 

My best guess is the problem is on line 735, but then my crystal ball has been at bit cloudy which makes it hard to read.....

 

 

Good luck with your project.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...