As any other microcontroller manufacturer, Infineon also provides the corresponding library with a certain set of functions to help you configure and control the internal AURIX peripherals, from the system clocks to all serial communication interfaces like the MCMCAN or the QSPI.

This library comes out of the box with the AURIX Studio and supports all the TC3x family of microcontrollers, like the one that comes with our AURIX TC37x Lite Kit.

Low Level Drivers

The most important part of the library is located at **Libraries/iLLD/TC37A/Tricore** (depends on your part number), here you can find folders for each peripheral, like the ADC, CAN, GPT, etc. These are mostly divided in two parts.

  • **Std folder:** This folder contains the most low level functions to configure the peripheral, most of the functions are used to access the registers of the peripheral. If you want to control at the most low level the peripheral, this is the folder you should look at.
  • **Peripheral:** This folder contains the specific functions to control the peripheral, like the ADC conversion, the CAN message transmission, etc. It is made to be more user friendly and to be used in a more high level way and to keep a layer of compatibility among the iLLD for other MCU families among the AURIXs. And by the way, this layer uses the functions from the Std folder.
.
└──── Can
    ├── Can
    │   ├── IfxCan_Can.h
    │   └── IfxCan_Can.c
    └──── Std
        ├── IfxCan.h
        └── IfxCan.c

The majority of the time you will be using the peripheral folder, here the library comes structured in two kind of function sets, the **init** and the **control** functions. The library uses structures to configure the peripherals, so you will need to create a structure, fill it with the desired values and pass it to the init function to configure the peripheral.
Let's see an example with the ADC peripheral. First you need to configure the ADC module using the IfxEvadc_Adc_Config structure, the IfxEvadc_Adc_initModuleConfig will set the default values for this structure ( some of them comes with a massive set of elements ), then you can explicitly modified the ones you need and pass it to the IfxEvadc_Adc_initModule function to configure the ADC module.

IfxEvadc_Adc_Config Adc_Config;
IfxEvadc_Adc Adc;
/* set the default configuration in Adc_Config */
IfxEvadc_Adc_initModuleConfig( &Adc_Config, &MODULE_EVADC );
/* Set some values according to your application */
Adc_Config.analogClockGenerationMode = IfxEvadc_AnalogClockGenerationMode_normal;
Adc_Config.supplyVoltage = IfxEvadc_SupplyVoltageLevelControl_upperVoltage;
/* Initialize module */
IfxEvadc_Adc_initModule( &Adc, &Adc_Config );

Adc comes divided in groups, and each group needs to be configured. The IfxEvadc_Adc_GroupConfig structure is used to configure the group, and it follows the same approach as the module configuration, you need to set the default values using the IfxEvadc_Adc_initGroupConfig function, then you can modify the values you need and pass it to the IfxEvadc_Adc_initGroup function to configure the given group.

IfxEvadc_Adc_GroupConfig Adc_Group_Config;
IfxEvadc_Adc_Group Adc_Group;
/* Set group configuration with default values */
IfxEvadc_Adc_initGroupConfig( &Adc_Group_Config );
/* Setting user configuration using group 0 */
Adc_Group_Config.groupId = IfxEvadc_GroupId_0;
Adc_Group_Config.master = IfxEvadc_GroupId_0;
/* Enable queued source */
Adc_Group_Config.arbiter.requestSlotQueue0Enabled = TRUE;
/* Enable all gates in "always" mode (no edge detection) */
Adc_Group_Config.queueRequest[0].triggerConfig.gatingMode = IfxEvadc_GatingMode_always;
/* Initialize the group */
IfxEvadc_Adc_initGroup( &Adc_Group, &Adc_Group_Config );

And each group comes divided into channels that needs to be configured. The IfxEvadc_Adc_ChannelConfig structure is used to configure the channel, and it follows the same approach as the module and group configuration.

IfxEvadc_Adc_ChannelConfig Adc_Channel_Config;
IfxEvadc_Adc_Channel Adc_Channel;

/* Initialize the configuration with default values */
IfxEvadc_Adc_initChannelConfig( &Adc_Channel_Config, &Adc_Group );
/* Select the channel ID and the respective result register */
Adc_Channel_Config.channelId = IfxEvadc_ChannelId_0;
Adc_Channel_Config.resultRegister = IfxEvadc_ChannelResult_0;
/* Initialize the channel */
IfxEvadc_Adc_initChannel( &Adc_Channel, &Adc_Channel_Config );

How many times this process will be repeated depends on the peripheral you are configuring, but the process is the same: create a structure, fill it with the desired values, and pass it to the init function to configure the peripheral. For instance, CAN modules are divided into nodes, which means that you will need to configure the CAN module and then the CAN node at least.
The control functions are basically the ones you will use to control the peripheral, like to start a conversion, to send a message, etc., once the peripheral has been configured.

/* Register the channel and its options to be converted */
IfxEvadc_Adc_addToQueue( &Adc_Channel, IfxEvadc_RequestSource_queue0, 0x00 );
/* Start the queue and trigger conversion by software */
IfxEvadc_Adc_startQueue( &Adc_Group, IfxEvadc_RequestSource_queue0 );
💡
There are some functionalities not covered by the functions from the peripheral folder. In this case, you can use the functions from the Std folder, which are more low level and give you more control over the peripheral.

The Pin Mapping files

There is an extra folder called _PinMap that contains the pin mapping files for the AURIX microcontroller. In these files, we can find a series of structures defining the pins that can be used for each peripheral, along with the required configuration values. For instance,

IfxCan_Rxd_In IfxCan_RXD00A_P02_1_IN = {&MODULE_CAN0, IfxCan_NodeId_0, {&MODULE_P02, 1}, Ifx_RxSel_a};
IfxCan_Txd_Out IfxCan_TXD00_P02_0_OUT = {&MODULE_CAN0, IfxCan_NodeId_0, {&MODULE_P02, 0}, IfxPort_OutputIdx_alt5};

These structure can used later on by the peripheral init functions to configure the pins for the peripheral.

/*Define a structure that contains the pins to be configured as CAN pins*/
IFX_CONST IfxCan_Can_Pins Can_Pins =
{
    .txPin      = &IfxCan_TXD10_P00_0_OUT,
    .txPinMode  = IfxPort_OutputMode_pushPull,
    .rxPin      = &IfxCan_RXD10C_P23_0_IN,
    .rxPinMode  = IfxPort_InputMode_pullUp,
    .padDriver  = IfxPort_PadDriver_cmosAutomotiveSpeed4
};

/*load default CAN node configuration into configuration structure*/
IfxCan_Can_initNodeConfig( &Can_Node_Config, &Can );
/*Set can configuration for node 0, baudrate, frame mode, etc..*/
Can_Node_Config.pins              = &Can_Pins
Can_Node_Config.baudRate.baudrate = 100000u;
Can_Node_Config.nodeId            = IfxCan_NodeId_0;              //Assign source CAN node to CAN node 1
Can_Node_Config.frame.mode        = IfxCan_FrameMode_standard;//Classic mode, 8 bytes frames
Can_Node_Config.frame.type        = IfxCan_FrameType_transmit;//define the frame to be the transmitting one
/* initialize the source CAN node with the modified configuration*/
IfxCan_Can_initNode( &Can_Node, &Can_Node_Config );

Register definitions

The library also provides the register definitions for the AURIX microcontroller, which can be found in the **Libraries/Infra/sfr** folder. These files contain the register definitions for each peripheral, which can be used to access the registers directly.

  • There are three files for each peripheral: one for the register definition, one for the bit definition, and one for the register map.
.
Sfr
└──── TC37A
    └── _Reg
        ├── IfxCan_bf.h
        ├── IfxCan_reg.h
        └── IfxCan_regdef.h

To access the registers directly, you can use the following syntax: <peripheral>.<register>.<acess type>, The access type can be either by bit fields or by 32 bits. module names can be found in the Ifx<peripheral>_reg.h file. and the bit fields can be found in the Ifx<peripheral>_regdef.h file.

/* access the 32 bits */
MODULE_CAN0.MCR.U = 0x00000001;

/*access by bit fields*/
MODULE_CAN0.MCR.B.CI = 1;
MODULE_CAN0.MCR.B.CCCE = 1;

Another way to access is through the Control structure, that is a pointer to the peripheral registers, and it is used to access the registers directly.

IfxCan_Can Can;

/* access the 32 bits */
Can.can->MCR.U = 0x00000001;
/*access by bit fields*/
Can.can->MCR.B.CI = 1;

Compiler and startup files

The library also provides the compiler and startup files for the AURIX microcontroller, which can be found in the **Libraries/Infra/Platform** & **Libraries/Infra/Ssw** folder. These files contain the necessary files to compile and link the code for the AURIX microcontroller using different Compilers including Tasking, Gcc, Higtec and Green Hills, this ensure that the code can be compiled, linked and migrated for the AURIX microcontroller using different compilers

/*in case you wonder, this is the first fucntion to execute fater a Power on reset in the core 0, file Ifx_Ssw_Tc0.c*/
void _START(void)
{
    Ifx_Ssw_jumpToFunction(__StartUpSoftware);
}

We write several examples using the iLLD library in the following chapters, with the aim to help you to learn how to configure and control the AURIX peripherals using the iLLD library.