Getting Started with LIN for RL78/F2x MCU's
Renesas provides software drivers and a configuration system for building LIN (Local Interconnect Network) applications for RL78 F23/24 MCU's. This page describes how to configure and build a basic LIN application in IAR EWARM.
Refer to this application note for more details and API reference: https://www.renesas.com/en/document/apn/rl78f2x-rlin3-module-software-integration-system
Hardware
This guide uses the RL78 F24 target board for both master and slave. https://www.renesas.com/en/products/microcontrollers-microprocessors/rl78-low-power-8-16-bit-mcus/rtk7f124fpc01000bj-rl78f24-r7f124fpj-target-board
When using LIN in master mode, the board needs to be modified such that R10 is a 1k Ohm resistor. Solder a pin in the +12V hole for the master. Solder pins in CN4 for both master and slave.
Smart Configurator
RLIN3 Module
Renesas provides an SIS module for RLIN3 that you will need to download and add to your project.
Module Configuration (Master)
Here you can configure basic settings for the RLIN3 peripheral and driver. F23 has only one available channel.
The LIN master requires you to configure an interval timer that drives the LIN scheduler. Set the interval value to your desired tick rate.
Port P53 is used to awaken the LIN transceiver.
Configure clock tree as shown:
Module Configuration (Slave)
The only difference for the slave is the timer configuration. The slave has no responsibility for running the schedule, but the driver does require a timer. Configure as shown:
LIN Configurator
The LIN Configurator executable is included with the download of the SIS module. In your project, a zip file containing the installer can be found under \smc_gen\r_rlin3\tool\en\.
The RLIN3 Smart Configurator module generates a header file containing your configurations. This file can be opened with LIN Configurator to get started. In LIN Configurator, click the "SMC Header File Open" button and select your header file "r_rlin3_config.h" in the src\r_rlin3_lib folder of your project.
Device and Channel Setup
Configure device and channel number(s):
Configure channel(s):
Configure baud rate:
Message and Schedule Setup
There are three types of message frames that can be configured in the message setup screen. This guide focuses on unconditional frames. Unconditional frames must be configured with a unique name, a publish/subscribe direction, an ID corresponding to the recipient slave device, a checksum type (enhanced by default), a data size in bytes, and initial data for each byte slot.
After frames are created and configured, at least one signal must be configured per frame. Frames may contain multiple signals. Each signal must have a unique name. In this example, FRM0 has a signal offset of 0 and a signal size of 8 corresponding to the number of data bits in the frame (1 byte). If you are to configure multiple signals per frame, offsets need to be set accordingly.
The RLIN3 driver sends and receives data by cycling through frames specified in a schedule table. Multiple schedules can be created but only one schedule can be active at any given time. Schedules must have unique names. In this example, there is a single frame in the schedule and it takes up a single frame slot. Longer frames that transfer arrays of data or have multiple signals may require multiple frame slots.
Saving Configuration
The save function under File→ Save allows you to store your configuration in XML format. This allows you to tweak your frames and schedules later on without having to reconfigure the entire system.
Generating Source Code
Source code generation can be performed by clicking the red, "Go" arrow or by selecting "Generate Source Code" under the "Tool" drop down. Source code generation will create a new IAR library project for each configured channel under r_lin_drv->ChannelX→liblin2.
Slave Configuration
The slave configuration requires a matching frame that in this case publishes instead of subscribing. The slave also requires you to configure a diagnostic frame before you can generate code.
Building the Library
Open the IAR IDE Workspace file generated from the LIN Configurator in IAR Embedded Workbench. Right click the root node in the workspace tree and select "Options...".
Under General Options→Target, configure your device variant and set the code and data model to "Far". By default, the linker script for your application will place the library code and data in the Far memory region.
Under C/C++ Compiler→Preprocessor, ensure the following symbols are defined. You can find more details about the preprocessor symbols in the RLIN3 application note.
With these options set, you can Make the project. This will output a linked library, liblin21s_IAR_0.a, under the Debug folder.
Building the Application
The RLIN3 Smart Configurator module populates a folder in src\smc_gen\r_rlin3_lib when you generate code with Smart Configurator. In order to use the code generated from LIN Configurator, it needs to be overwritten into the src\smc_gen\r_rlin3_lib folder from the src\r_rlin3_lib folder. This needs to be done every time after making changes and regenerating code in Smart Configurator.
After placing the generated library code in the smc_gen folder, open the application project in IAR Embedded Workbench. Right click the root node in the Workspace file tree and select "Options...". Navigate to Linker→Library. Under "Additional Libraries", add the path to the linked library file "liblin21s_IAR_0.a" that was built from the LIN Configurator library project.
Under "General Options→Target", set the correct device and set the code and data models to "Far" unless you have otherwise modified the linker script.
Now you should be able to successfully build the application project with the library code properly linked.
Using the Driver
Master Application
The LIN driver for the master application requires some setup before it can start sending and receiving messages.
In main.c:
Initialize the LIN driver with
l_sys_init()Initialize the channel interface with
l_ifc_init( LIN_CHANNEL0 )The LIN transceiver on the F24 FPB needs to be awoken by setting the P53 pin high:
P5_bit.no3 = 1;Set the LIN schedule to the one that was configured in the LIN Configurator. By default, the active schedule is an empty placeholder schedule:
l_sch_set(LIN_CHANNEL0, SCH0, 1);Create and start the timer that runs the scheduling ticks:
R_Config_TAU0_1_Create(); R_Config_TAU0_1_Start();Now you should be able to read data in the main loop:
data = l_u8_rd(SIG0);
In Config_TAU0_1_user.c:
Schedule ticks with
uint8_t tick_status = l_sch_tick(LIN_CHANNEL0);
main.c
#include "r_smc_entry.h"
#include "Config_TAU0_1.h"
#include "conflin_0.h"
#include "src/r_rlin3_lib/r_lin_drv/Channel0/conf/conflin_0.h"
int main(void)
{
// LIN Init
if( l_sys_init() )
{
P6_bit.no7 = 1;
}
else
{
if( l_ifc_init( LIN_CHANNEL0 ) )
{
P6_bit.no7 = 1;
}
else
{
// Wakeup LIN transceiver
P5_bit.no3 = 1;
// Set schedule
l_sch_set(LIN_CHANNEL0, SCH0, 1);
// LIN Master Schedule Timer
R_Config_TAU0_1_Create();
R_Config_TAU0_1_Start();
}
}
uint8_t data = 0;
EI();
while(1)
{
// Sleep if bus is idle
if (ld_is_ready(LIN_CHANNEL0) == LD_SERVICE_IDLE)
{
l_ifc_goto_sleep(LIN_CHANNEL0);
}
// Read data
data = l_u8_rd(SIG0);
}
}Config_TAU0_1_user.c
__interrupt static void r_Config_TAU0_1_interrupt(void)
{
/* Start user code for r_Config_TAU0_1_interrupt. Do not edit comment generated here */
if ( (l_ifc_read_status(LIN_CHANNEL0) & LD_MASK_SLEEP) == LD_MASK_SLEEP )
{
l_ifc_wake_up(LIN_CHANNEL0);
}
uint8_t tick_status = l_sch_tick(LIN_CHANNEL0);
uint16_t ifc_status = l_ifc_read_status(LIN_CHANNEL0);
uint8_t ready_status = ld_is_ready(LIN_CHANNEL0);
if (ready_status)
{
P6_bit.no7 = 0;
}
P6_bit.no6 = ( P6_bit.no6 == 0 ) ? 1 : 0;
/* End user code. Do not edit comment generated here */
}Slave Application
The slave application requires very similar setup to the master application, sans the schedule timer.
main.c
#include "r_smc_entry.h"
#include "conflin_0.h"
int main(void)
{
// LIN Init
if( l_sys_init() )
{
P6_bit.no7 = 1;
}
else
{
if( l_ifc_init( LIN_CHANNEL0 ) )
{
P6_bit.no7 = 1;
}
else
{
// Wakeup LIN transceiver
P5_bit.no3 = 1;
}
}
uint8_t data = 0x55;
uint16_t ifc_status;
EI();
while(1)
{
// Write data
l_u8_wr(SIG0, data);
ifc_status = l_ifc_read_status(LIN_CHANNEL0);
}
}