CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

Problem with LIN communication

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
HARSHAL KHAJONE



Joined: 16 Feb 2018
Posts: 7
Location: Pune

View user's profile Send private message Send e-mail

Problem with LIN communication
PostPosted: Fri Feb 16, 2018 9:24 am     Reply with quote

Below are my code which I changed for PIC18f46k22 using PIC16F690 code in ccs example


Code:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

LIN BUS Master


#include <18f46k22.h>


#FUSES NOWDT //No Watch Dog Timer
#FUSES HSM //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code protected from reads
#FUSES NOBROWNOUT //Reset when brownout detected
#FUSES NOPUT //No Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOIESO //Internal External Switch Over mode enabled
#FUSES NOFCMEN //Fail-safe clock monitor enabled
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES MCLR //Master Clear pin enabled
#FUSES NOXINST //Extended set extension and Indexed Addressing mode enabled
#FUSES NOPLLEN

#use delay(clock=8000000)
#use rs232(uart1, baud=9600, PARITY=N, Xmit=Pin_C6, RCV=Pin_C7, ERRORS)


#include "LINBUS1.h"

void main()
{
int i,msg_length, id_byte, addr, temp;
int16 adc_val;

int data[8];
int slave_addr = SLAVE_ADDRESS;
int8 command[2]={0xCC,0xA1}; // This command is not of much significanceA1
msg_length = 8; // NOTE - Message Length can only be 2,4 or 8 bytes long

setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
setup_comparator(NC_NC_NC_NC);

while(1)
{
delay_ms(300);
output_low(MCP201_CS);
delay_ms(2);// Toggle the CS pin at least 1 ms after wake-up
output_high(MCP201_CS);

delay_ms(200);
setup_uart(UART_SEND_BREAK); //This sends a break character (zero for 12 bit time)
temp=getc(); // Do a read after each write to clear RCREG
// Send Dummy character - Automatically gets set to zero
// putc(0x00); // The later version(4.???) of the compiler will send a putc automatically after UART_SEND_BREAK command
// not required in new version of software
// delay_ms(3);
linbus_generate_synchfield(); // Send Sync Character immediately after break
temp=getc(); // Do a read after each write to clear RCREG

delay_ms(10); // Set delay - Allow slaves to respond

// Initialize the message length
msg_length =2;

while(1)
{
delay_ms(100);

// Send command to slave to read ADC
//The following function Calculates the ID byte, and
// transmits the data, followed by the checksum
Lin_bus_transmit_data(MASTER_ADDRESS, msg_length, &COMMAND[0]);

delay_ms(5); // wait for slave to complete task

// Perform read routine
// Clear Read Interrupt
// clear_interrupt(INT_RDA);



id_byte = read_ident_byte();

msg_length = get_message_length(id_byte);

Errorflag =0; // Reset Error flag
Check_parity_bits(id_byte);
addr = address_match(id_byte);

if(addr == MASTER_ADDRESS)
{

read_data_packet(&data[0], msg_length);


linbus_verify_checksum(&data[0],msg_length);



// Use Pin D6 and D7 to display the received data
#use rs232(uart2, baud=9600, Xmit=Pin_D6, RCV=Pin_D7,ERRORS)
if(Errorflag!=0)
{
putc(Errorflag);
break;
}
else
{
delay_ms(5);
adc_val = make16(data[1],data[0]);
printf("\n\r ADC Value Slave - %lu",adc_val);
}
#use rs232(uart1, baud=9600, Xmit=Pin_C6, RCV=Pin_C7,ERRORS)

}
}
}
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

LIN Bus Slave



#include <18f46K22.h> //16F690.h


#FUSES NOWDT //No Watch Dog Timer
#FUSES HSM //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code protected from reads
#FUSES NOBROWNOUT //Reset when brownout detected
#FUSES NOPUT //No Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOIESO //Internal External Switch Over mode enabled
#FUSES NOFCMEN //Fail-safe clock monitor enabled
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES MCLR //Master Clear pin enabled
#FUSES NOXINST //Extended set extension and Indexed Addressing mode enabled
#FUSES NOPLLEN

#device ADC=10
#use delay(clock=8000000)
#use rs232(baud=9600,UART1, PARITY=N, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#include"LINBUS1.h"

// Function Prototypes
void Transmit_adc_value();


void main()
{
int8 id_byte, msg_length, addr, SPBRG1_temp, temp;
int8 data[8];

setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
setup_comparator(NC_NC_NC_NC);

while(1)
{
delay_ms(300);
output_low(MCP201_CS);
delay_ms(2); // Toggle the CS pin at least 1 ms after wake-up
output_high(MCP201_CS);
wait_for_master();
delay_ms(10);

//Desired Baud rate range - 1200 baud - 19200
// if((SPBRG < 5)|| (SPBRG>104))
// wait_for_master();

// Work-around for Errata
SPBRG1= SPBRG1-1; // Subtract 1 to get correct Baud Rate- Refer Errata sheet //SPBRG= SPBRG-1

SPBRG1_temp = SPBRG1; // Read SPBRG and write back to SPBRG (see errata) //SPBRG_temp = SPBRG;
SPBRG1 = SPBRG1_temp; //SPBRG = SPBRG_temp;
TXEN = 1; // Set the TXEN bit to enable the transmitter (See Errata)

while(1)
{
id_byte = read_ident_byte();


msg_length = get_message_length(id_byte);

Errorflag =0; // Reset Error Flag
Check_parity_bits(id_byte);
addr = address_match(id_byte);

if (Errorflag==0)
{


if(addr== SLAVE_ADDRESS || addr==MASTER_ADDRESS)

{

read_data_packet(&data[0], msg_length);


linbus_verify_checksum(&data[0],msg_length);


if(addr==MASTER_ADDRESS)

Transmit_adc_value();
delay_ms(5); // not required
temp=getc(); 

}
else

break; // If Address match does not occur, RESET states

}
else // DEBUG Pulse on RC5
{
output_high(Pin_C5);
delay_ms(1);
output_low(Pin_C5);
}

}
}
}


//This function will read 10 bit ADC value from AN0 and transmit it to Master
void Transmit_adc_value()
{
int16 adc_val;
int8 reply[2];

int8 msg_length = 2; // Length of Response

// Init
reply[0]=0;
reply[1]=0;

// ADC ports initialization
setup_port_a(ALL_ANALOG);
setup_adc(adc_clock_internal);
set_adc_channel(0);
delay_ms(1);
adc_val = read_adc();


reply[0] = make8(adc_val,0);
reply[1] = make8(adc_val,1);
reply[1]= reply[1] & 0x03; // set to 10 bit output

delay_ms(4);
setup_port_a(NO_ANALOGS);
setup_adc(ADC_OFF);
make_all_pins_digital();
// Transmit the acquired data over LIN bus
Lin_bus_transmit_data(MASTER_ADDRESS, msg_length, &reply[0]);

}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

LIN bus driver



#define SLAVE_ADDRESS 0x05
#define MASTER_ADDRESS 0X00

// CS/WAKE Pin for MCP201
#define MCP201_CS Pin_C4


// Slave Definitions for Error Flags
byte Errorflag;

#bit ID_Parity_error = Errorflag.0
#bit bit_error = Errorflag.1
#bit CRC_error = Errorflag.2
#bit data_received = Errorflag.3
#bit addr_match = Errorflag.4

// Special Function Registers
#byte BAUDCON1 = 0x9B       //BAUDCTL= 0x9B
#bit WUE = BAUDCON1.1
#bit RCIDL = BAUDCON1.6

#byte PIR1 = 0x0C
#bit RC1IF = PIR1.5       //RCIF
#byte SPBRG1 = 0x99       //SPBRG
#byte SPBRGH1 = 0x9A       //SPBRGH
#byte TXSTA1 = 0x98       //TXSTA
#byte RCREG1 = 0xFAE       //RCREG=0x1A (0x1A is a Address of RCREG)FAE

#bit TXEN = TXSTA1.5

//Function Prototypes//
void linbus_generate_synchfield();
void wait_for_master();
int read_ident_byte();
void Check_parity_bits(int ident_byte);
int address_match(int8 ident_byte);
void read_data_packet(int ident_byte, int *ptr, int msg_length);
int8 linbus_calculate_checksum(byte* databytes, int8 message_length);
int8 linbus_calculate_ident_field(int8 device_address, int8 message_length);
int8 linbus_calculate_ident_parity(int8 ident_byte);
int get_message_length(int id_byte);
void Lin_bus_transmit_data(int device_addr, int msg_length, int8* ptr);

void output_debug(void);


// Macro for Chip Select - for MCP201 chip, CS connected to Pin_C3
#define Chip_SelectMCP201() output_float(MCP201_CS)

#define Disable_MCP201(x) bit_clear(*(x/8+0x80),x%8)



/*
void linbus_generate_synchfield()
This function will transmit a Sync Character 'U' after a SYNC break
PARAMS: none
RETURNS: none
*/
void linbus_generate_synchfield()
{
putc(0x55);
}

/*
void wait_for_master()
This functions puts the Slave receiver in Wake-Up on RDA mode
and the receiver is setup to auto detect the baud rate
PARAMS: none
RETURNS: none
*/

void wait_for_master()
{
int garbage;
setup_uart(UART_WAKEUP_ON_RDA);
SPBRG1 = 0;       // Clear the baud rate gen register - Errata//SPBRG
SPBRGH1 = 0;       //SPBRGH
TXEN = 0;       //Clear the TXEN bit to disable the transmitter - Errata
RC1IF=0;       //RCIF
while(!RC1IF);       //while(!RCIF);
WUE=0;       // Manually clear the WUE bit - Errata

garbage = getc();       //RCIF is cleared with a read of RCREG
setup_uart(UART_AUTODETECT_NOWAIT);       // Auto Detect the baud rate
while(!RC1IF);       // Verify baud rate was measured - RCIF set from byte received //while(!RCIF);
garbage=getc();

}
/*
int read_ident_byte()
This function is called after wait_for_master() to read the ID byte
PARAMS: none
RETURNS: ID byte
*/
int read_ident_byte()
{
int id_byte;
id_byte = getc();

return(id_byte);
}

/*
void Check_parity_bits(int ident_byte)
This function verifies the parity bits of the received ID byte
and sets the errorflag if error is present
PARAMS: none
RETURNS: none
*/
void Check_parity_bits(int ident_byte)
{
int parity, temp_parity;
parity = ident_byte & 0xC0;
temp_parity = ( ( (ident_byte >> 0) ^ (ident_byte >> 1) ^ (ident_byte >> 2)
^ (ident_byte >> 4) ) & 0x01 ) << 6 ;       // parity bit6
temp_parity |= ( ( (ident_byte >> 1) ^ (ident_byte >> 3) ^ (ident_byte >> 4)
^ (ident_byte >> 5) ) & 0x01 ) << 7;       // parity bit 7


if(temp_parity == parity)
ID_Parity_error =0; // Reset Parity Error
else
ID_Parity_error =0; // Set Parity Error
}

/*
int address_match(int8 ident_byte)
The receiver checks the ID byte bits 0-3 for a address match
PARAMS: none
RETURNS: addr
*/
int address_match(int8 ident_byte)
{
int addr;
addr = ident_byte & 0x0F;
if (addr==MASTER_ADDRESS || addr==SLAVE_ADDRESS) // slave_addr is defined at top of header file
addr_match=0;
else
addr_match =1;
return(addr);

}

/*
void read_data_packet(int *ptr, int msg_length)
This function will read the data packet
PARAMS *ptr: Address where data will get stored
PARAMS msg_length: Length of the message
RETURNS: none
*/
void read_data_packet(int *ptr, int msg_length)
{
int i; // This is the number of bytes of data - 2,4 or 8
data_received =1;
for(i=0;i<msg_length;i++)
{
*ptr =getc();
ptr++;
if(i== (msg_length-1)) // Set the data received bit
data_received=0; // once reception is complete
}
}//////////

/*
int8 linbus_calculate_checksum (byte* databytes, int8 message_length)
This function will calculate checksum for received data
PARAMS databytes: The received data bytes
PARAMS message_length: Length of message
RETURNS: 8 bit inverted module -255 checksum
*/
int8 linbus_calculate_checksum (byte* databytes, int8 message_length)
{
int8 i;
int8 sum;

sum = 0;

for (i=0; i<message_length; i++)
{
sum += databytes[i];
}

sum = 0-sum;

return sum;
}

/*
int8 linbus_calculate_ident_field(int8 device_address, int8 message_length )
This function will assemble the ID byte from the address and data length
PARAMS device_address: address of the device
PARAMS message_length: Length of message
RETURNS: Assembled ID byte
*/
int8 linbus_calculate_ident_field(int8 device_address, int8 message_length )
{
int8 ident_byte;
if(message_length==8)
message_length=0x03;
else if(message_length==4)
message_length=0x02;
else if(message_length==2)
message_length=0x01;

ident_byte = (device_address & 0x0F) | ((message_length & 0x03)<<4);

ident_byte |= linbus_calculate_ident_parity (ident_byte);

return ident_byte;
}

/*
int8 linbus_calculate_ident_parity(int8 ident_byte )
This function calculates the ident field parity according to specification
The parity is returned in bit 7 and 6 according the specification, all other bits are unset
this parity should be checked even in the receiver
PARAMS ident_byte: The ID byte containing 6 bits of information (0-5)
RETURNS: Parity inserted into the ID byte (Final ID byte)
*/
int8 linbus_calculate_ident_parity(int8 ident_byte )
{
int8 parity;

parity = ( ( (ident_byte >> 0) ^ (ident_byte >> 1) ^ (ident_byte >> 2)
^ (ident_byte >> 4) ) & 0x01 ) << 6 ; // parity bit6
parity |= ( ( (ident_byte >> 1) ^ (ident_byte >> 3) ^ (ident_byte >> 4)
^ (ident_byte >> 5) ) & 0x01 ) << 7 ; // parity bit 7
return parity;
}

/*
void linbus_verify_checksum(byte* databytes, int8 message_length)
This function will verify the checksum of the data received
Call this function after read_data_packet()
PARAMS databytes: Received Data
PARAMS message_length: Length of message
RETURNS: none
This function will set the CRC_error bit in Errorflag if it detect checksum error
*/
void linbus_verify_checksum(byte* databytes, int8 message_length)
{
int CRC, CRC_actual;
CRC_actual = getc();
CRC = linbus_calculate_checksum(&databytes[0], message_length);
if(CRC_actual==CRC)
CRC_error =0;
else
CRC_error =0;
}


/*
int get_message_length(int id_byte)
This function will extract Message Length from the ID Byte
PARAMS id_byte: The ID byte
RETURNS msg_length: The message length
*/
int get_message_length(int id_byte)
{
int ident_byte, msg_length;
ident_byte = ((id_byte&0x30)>>4);
if(ident_byte==0||ident_byte==1)
msg_length =2;
if(ident_byte==2)
msg_length =4;
if(ident_byte==3)
msg_length=8;
return(msg_length);
}

/*
void Lin_bus_transmit_data(int device_addr, int msg_length, int8* ptr)
The following function Calculates the ID byte, and
transmits the data, followed by the checksum
PARAMS device_addr: address of device
PARAMS msg_length: Length of message
PARAMS ptr: Data to be transmitted
RETURNS: none
*/
void Lin_bus_transmit_data(int device_addr, int msg_length, int8* ptr)
{
int id_byte, CRC,i, temp;
id_byte = linbus_calculate_ident_field(device_addr, msg_length);

putc(id_byte); // Put the ID byte on the Line
temp=getc(); // Do a read after each write to clear RCREG
delay_ms(5);

for(i=0;i<msg_length;i++)
{
putc(ptr[i]); // Put the Data bytes on the Line
temp=getc(); // Do a read after each write to clear RCREG
}

delay_ms(5);
// calculate the CRC of the Data to be transmitted
CRC = linbus_calculate_checksum(&ptr[0], msg_length);
putc(CRC); // // Put the CRC byte on the Line
temp=getc(); // Do a read afvter each write to clear RCREG

}

void output_debug(void)
{
output_high(Pin_C5);
delay_us(50);
output_low(Pin_C5);
}
temtronic



Joined: 01 Jul 2010
Posts: 6329
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Feb 16, 2018 11:51 am     Reply with quote

from the LIN driver....
#byte PIR1 = 0x0C

that's NOT the PIR1 for an 18F46K22 according to my datasheet copy...
maybe others can confirm but I'm guessing that's part of your problem.
I didn't check any others but registers for that PIC are 3 characters long, usually 0xFxx .....

Hopefully you still have original LIN driver to copy THEN edit the NEW version !

This is one reason why I suggested the 'try 690 PICs, then 46 master then 46 slave....even just ONE incorrect variable or register and it won't work.

Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 20421

View user's profile Send private message

PostPosted: Fri Feb 16, 2018 11:52 am     Reply with quote

Most of these register addresses are wrong for the 18F46K22. Most
of them are for the 16F690.
Quote:

// Special Function Registers
#byte BAUDCON1 = 0x9B //BAUDCTL= 0x9B
#bit WUE = BAUDCON1.1
#bit RCIDL = BAUDCON1.6

#byte PIR1 = 0x0C
#bit RC1IF = PIR1.5 //RCIF
#byte SPBRG1 = 0x99 //SPBRG
#byte SPBRGH1 = 0x9A //SPBRGH
#byte TXSTA1 = 0x98 //TXSTA
#byte RCREG1 = 0xFAE //RCREG=0x1A (0x1A is a Address of RCREG)FAE

#bit TXEN = TXSTA1.5

You can fix these errors by using getenv() to get the register addresses
instead of hard-coding them. Example:
Code:
#byte PIR1 = getenv("SFR:PIR1")


The #bit statements are correct. You don't have to change them.
Just fix the #byte statements.
HARSHAL KHAJONE



Joined: 16 Feb 2018
Posts: 7
Location: Pune

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 16, 2018 10:36 pm     Reply with quote

temtronic wrote:
from the LIN driver....
#byte PIR1 = 0x0C

that's NOT the PIR1 for an 18F46K22 according to my datasheet copy...
maybe others can confirm but I'm guessing that's part of your problem.
I didn't check any others but registers for that PIC are 3 characters long, usually 0xFxx .....

Hopefully you still have original LIN driver to copy THEN edit the NEW version !

This is one reason why I suggested the 'try 690 PICs, then 46 master then 46 slave....even just ONE incorrect variable or register and it won't work.

Thanks a lot temtronic, after changing correction as you say and other register address code get run successfully Laughing

Thanks again for your support, keep supporting me i'm newer in PIC


Last edited by HARSHAL KHAJONE on Fri Feb 16, 2018 10:42 pm; edited 1 time in total
HARSHAL KHAJONE



Joined: 16 Feb 2018
Posts: 7
Location: Pune

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 16, 2018 10:41 pm     Reply with quote

PCM programmer wrote:
Most of these register addresses are wrong for the 18F46K22. Most
of them are for the 16F690.
Quote:

// Special Function Registers
#byte BAUDCON1 = 0x9B //BAUDCTL= 0x9B
#bit WUE = BAUDCON1.1
#bit RCIDL = BAUDCON1.6

#byte PIR1 = 0x0C
#bit RC1IF = PIR1.5 //RCIF
#byte SPBRG1 = 0x99 //SPBRG
#byte SPBRGH1 = 0x9A //SPBRGH
#byte TXSTA1 = 0x98 //TXSTA
#byte RCREG1 = 0xFAE //RCREG=0x1A (0x1A is a Address of RCREG)FAE

#bit TXEN = TXSTA1.5

You can fix these errors by using getenv() to get the register addresses
instead of hard-coding them. Example:
Code:
#byte PIR1 = getenv("SFR:PIR1")


The #bit statements are correct. You don't have to change them.
Just fix the #byte statements.


Thank you PCM programmer for your support, the fault was address of register that is solve Smile
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group