S32K144 Peripherals

Table of Contents

Objective

So hello guys, welcome back to NXP Semiconductors S32K144 MCU Tutorial series. In the last blog we just started with S32K144 MCU. In this blog we are going to explore the clock peripheral of this MCU. Going to Start with Clock peripheral. Objective would be to get

  • familiarity with clock peripheral for S32K144 MCU.
  • How to do clock configuration in S32K144 MCU using S32 Design Studio Config tools.
  • Going to understand the how to use GPIO peripheral via S32K SDK/pins driver.
  • Would also be demonstrating the blink LED sketch for GPIO in the end.

Clock Peripheral in S32K144

The clock peripherals of S32k1xx have 3 modules that configure the clocks of the S32K1xx MCU’s.

The clock peripherals are basically divided into three modules 

  • System clock generator
  • Low power oscillator
  • Peripheral clock control

System clock generator: – This Module generates the Core system clock which is the most important and crucial part. Via this Core system clock, all the peripherals get the clock frequency. So, for generating core system clocks there are 4 sources that can be done. The SCG supports four clock sources, as below:

  1. System Oscillator(SOSC):– the system oscillator in conjunction with an external crystal or resonator. That generates a reference clock for the MCU. The frequency of SOSC lies in between XTAL & EXTAL…
  2. Fast internal reference clock (FIRC_CLK):- an internally generated 48MHZ clock, which can be used as a clock source for other on-chip peripherals.
  3. Slow internal reference clock (SIRC_CLK):– an internally generated 8MHZ clock, which can be used as a clock source for other on-chip peripherals.
  4. System phase-locked loop (SPLL):– phase-locked loop that has a VCO(voltage-controlled oscillator) that generates an output signal whose frequency can be adjusted by an input voltage.

Peripheral clock control (PCC):- This module basically configures, controls, and generates the clock for all the peripherals of the MCU via system clock frequency. To conserve the power most modules’ clocks can be turned off by configuring the CGC field of the peripheral control register in the PCC module. These fields are cleared after any reset, which disables the peripheral clock of the corresponding module.

Note: We will be mainly focusing on the above two clock modules only for our initial development. Understanding and learning.

Low power oscillator (LPO):- an internally generated low power oscillator clock with a typical frequency of 128 kHz which can be used as the clock source for modules operational in low power modes.

How to configure clock peripheral in S32K144 using S32 Design Studio IDE

Clock peripheral of S32K144 MCU can be configured using the Clock Configuration tools of S32 Design Studio. These tools provide us with the GUI interface to configure the clock of the MCU. To know in detail about the clock configuration of S32 Design Studio refer to these.

Clock diagram View
In the clock diagram we can configure the frequency of MCU using the clock tree.This view would be used in this blog for doing system and core clock configuration of MCU.
Click Here
Clock Table View
In clock table, view we can see the clock frequency in tabular format of all clock sources and clock outputs of the Microcontrller. This view would be used for seeing summary of system and clock configuration.
Click Here
clock peripheral
In clock peripheral we can see all the clock frequency that is set by us to configure output clock. This view would not be used in the systema nd clock configuration, this view is mainly for peripheral clock configuration.
Click Here
Clock Consumer View
In clock consumer we can see all the input & output clock in tabular form.This view would not be used in the systema nd clock configuration, this view is mainly for peripheral clock configuration.
Click Here
Previous slide
Next slide

For Demonstration purpose on how to do the Clock Configuration in S32 Design Studio, using the hello world demo example from GPIO Peripheral of S32K144 and configuring its core clock with 16 MHZ external crystal oscillator using SPLL.

Clock Configuration Header and Source Files

So, as if now we have configured the clock peripheral of the S32K144 MCU, without actually writing any code and just by using S32 Clock Configuration Tool, by just having understanding of the theory of Clock peripheral of our corresponding S32K Microcontroller!!. Isn’t that interesting.

Lets now just see what code is generated and how is generated code gonna configure our controller.

  • clock_config.h: contains the macros and variable declaration that will store the input values for clock peripheral.
				
					#ifndef CLOCK_CONFIG_H
#define CLOCK_CONFIG_H

#include "clock.h"
#include <stdbool.h>
#include <stdint.h>


/**
 * @page misra_violations MISRA-C:2012 violations
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 2.5, Global macro not referenced.
 * Application or driver example may not use all symbols that are 
 * generated by configurations generator.
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 8.11, When an array with external linkage
 * is declared, its size should be explicitly specified.
 * The number of configurations/callbacks can be zero. 
 * On the other side C language forbids declaring array of size zero.
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 8.7, External variable could be made static.
 * The external variables will be used in other source files in application code.
 *
 */

/*! @brief Count of user configuration structures */
#define CLOCK_MANAGER_CONFIG_CNT                           1U /*!< Count of user configuration */

/*! @brief Count of user Callbacks structures */
#define CLOCK_MANAGER_CALLBACK_CNT                         0U /*!< Count of user Callbacks */


/*! @brief Count of peripheral clock user configuration 0*/
#define NUM_OF_PERIPHERAL_CLOCKS_0                         32U /* Count of peripheral clock user configurations. */

/*! @brief User configuration structure 0*/
extern clock_manager_user_config_t clockMan1_InitConfig0;

/*! @brief User peripheral configuration structure 0*/
extern peripheral_clock_config_t peripheralClockConfig0[NUM_OF_PERIPHERAL_CLOCKS_0];

/*! @brief Array of User callbacks */
/* The tool do not support generate Callbacks configuration. It's always empty. */
extern clock_manager_callback_user_config_t *g_clockManCallbacksArr[];

/*! @brief Array of pointers to User configuration structures */
extern clock_manager_user_config_t const *g_clockManConfigsArr[CLOCK_MANAGER_CONFIG_CNT];

#endif /* CLOCK_CONFIG_H */

				
			

Their are 2 important variables, clockMan1_InitConfig0 and peripheralClockConfig0, which are objects of the structures clock_manager_user_config_t and peripheral_clock_config_t.

Both of these structure conatins the various data fields for configuring the clock. To see the defination of these structure, see file clock_S32K1xx.h

  • clock_config.c: contains the defination and initialization values for the variables that are declared in .h file. 

Both of these variables clockMan1_InitConfig0 and peripheralClockConfig0  are initialized in this file.

				
					/**
* @page misra_violations MISRA-C:2012 violations
*
* @section [global]
* Violates MISRA 2012 Required Rule 9.4, Duplicate initialization of object element.
* It's the only way to initialize an array that is member of struct.
*
* @section [global]
* Violates MISRA 2012 Advisory Rule 8.7, External variable could be made static.
* The external variables will be used in other source files in application code.
*/

/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
product: Clocks v8.0
processor: S32K144
package_id: S32K144_LQFP100
mcu_data: s32sdk_s32k1xx_rtm_403
processor_version: 0.0.0
 * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/

#include "clock_config.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!Configuration
name: BOARD_BootClockRUN
called_from_default_init: true
outputs:
- {id: ADC0_CLK.outFreq, value: 8 MHz}
- {id: ADC1_CLK.outFreq, value: 8 MHz}
- {id: BUS_CLK.outFreq, value: 16 MHz}
- {id: CLKOUT.outFreq, value: 48 MHz}
- {id: CMP0_CLK.outFreq, value: 16 MHz}
- {id: CORE_CLK.outFreq, value: 32 MHz}
- {id: CRC0_CLK.outFreq, value: 16 MHz}
- {id: DMA0_CLK.outFreq, value: 32 MHz}
- {id: DMAMUX0_CLK.outFreq, value: 16 MHz}
- {id: EIM0_CLK.outFreq, value: 32 MHz}
- {id: ERM0_CLK.outFreq, value: 32 MHz}
- {id: EWM0_CLK.outFreq, value: 16 MHz}
- {id: FIRCDIV1_CLK.outFreq, value: 48 MHz}
- {id: FIRCDIV2_CLK.outFreq, value: 48 MHz}
- {id: FLASH_CLK.outFreq, value: 8 MHz}
- {id: FLEXCAN0_CLK.outFreq, value: 32 MHz}
- {id: FLEXCAN1_CLK.outFreq, value: 32 MHz}
- {id: FLEXCAN2_CLK.outFreq, value: 32 MHz}
- {id: FTFC0_CLK.outFreq, value: 8 MHz}
- {id: FTM0_CLK.outFreq, value: 8 MHz}
- {id: FTM1_CLK.outFreq, value: 8 MHz}
- {id: FTM2_CLK.outFreq, value: 8 MHz}
- {id: FTM3_CLK.outFreq, value: 8 MHz}
- {id: FlexIO0_CLK.outFreq, value: 8 MHz}
- {id: LPI2C0_CLK.outFreq, value: 8 MHz}
- {id: LPIT0_CLK.outFreq, value: 8 MHz}
- {id: LPO_1K_CLK.outFreq, value: 1 kHz}
- {id: LPO_CLK.outFreq, value: 128 kHz}
- {id: LPSPI0_CLK.outFreq, value: 8 MHz}
- {id: LPSPI1_CLK.outFreq, value: 8 MHz}
- {id: LPSPI2_CLK.outFreq, value: 8 MHz}
- {id: LPTMR0_CLK.outFreq, value: 8 MHz}
- {id: LPUART0_CLK.outFreq, value: 16 MHz}
- {id: LPUART1_CLK.outFreq, value: 16 MHz}
- {id: LPUART2_CLK.outFreq, value: 8 MHz}
- {id: MPU0_CLK.outFreq, value: 32 MHz}
- {id: MSCM0_CLK.outFreq, value: 32 MHz}
- {id: PDB0_CLK.outFreq, value: 32 MHz}
- {id: PDB1_CLK.outFreq, value: 32 MHz}
- {id: PORTA_CLK.outFreq, value: 16 MHz}
- {id: PORTB_CLK.outFreq, value: 16 MHz}
- {id: PORTC_CLK.outFreq, value: 16 MHz}
- {id: PORTD_CLK.outFreq, value: 16 MHz}
- {id: PORTE_CLK.outFreq, value: 16 MHz}
- {id: RTC0_CLK.outFreq, value: 16 MHz}
- {id: RTC_CLK.outFreq, value: 48 MHz}
- {id: SCGCLKOUT.outFreq, value: 48 MHz}
- {id: SIRCDIV1_CLK.outFreq, value: 8 MHz}
- {id: SIRCDIV2_CLK.outFreq, value: 8 MHz}
- {id: SOSCDIV1_CLK.outFreq, value: 16 MHz}
- {id: SOSCDIV2_CLK.outFreq, value: 16 MHz}
- {id: SPLLDIV1_CLK.outFreq, value: 48 MHz}
- {id: SPLLDIV2_CLK.outFreq, value: 24 MHz}
- {id: SPLL_CLK_OUT.outFreq, value: 96 MHz}
- {id: SYS_CLK.outFreq, value: 32 MHz}
- {id: TRACE_CLK.outFreq, value: 32 MHz}
settings:
- {id: powerMode, value: HSRUN}
- {id: 'HSRUN:SCG.DIVBUS.scale', value: '2', locked: true}
- {id: 'HSRUN:SCG.DIVCORE.scale', value: '3', locked: true}
- {id: 'HSRUN:SCG.DIVSLOW.scale', value: '4', locked: true}
- {id: 'HSRUN:SCG.SCSSEL.sel', value: SCG.SPLL_CLK}
- {id: PCC.LPTMR0_FRAC.scale, value: '1', locked: true}
- {id: PCC.LPUART0_CLK_SEL.sel, value: SCG.SOSCDIV2_CLK}
- {id: PCC.LPUART1_CLK_SEL.sel, value: SCG.SOSCDIV2_CLK}
- {id: PCC.PREDIV.scale, value: '1', locked: true}
- {id: PCC.PREDIVTRACE.scale, value: '1', locked: true}
- {id: PCC.TRACE_FRAC.scale, value: '1', locked: true}
- {id: RTCCLKSEL.sel, value: SCG.FIRCDIV1_CLK}
- {id: 'RUN:SCG.DIVBUS.scale', value: '1', locked: true}
- {id: 'RUN:SCG.DIVCORE.scale', value: '6', locked: true}
- {id: 'RUN:SCG.DIVSLOW.scale', value: '2', locked: true}
- {id: 'RUN:SCG.SCSSEL.sel', value: SCG.SPLL_CLK}
- {id: SCG.DIVBUS.scale, value: '2', locked: true}
- {id: SCG.DIVCORE.scale, value: '3', locked: true}
- {id: SCG.DIVSLOW.scale, value: '4', locked: true}
- {id: SCG.FIRCDIV1.scale, value: '1', locked: true}
- {id: SCG.FIRCDIV2.scale, value: '1', locked: true}
- {id: SCG.PREDIV.scale, value: '2', locked: true}
- {id: SCG.SCSSEL.sel, value: SCG.SPLL_CLK}
- {id: SCG.SIRCDIV1.scale, value: '1', locked: true}
- {id: SCG.SIRCDIV2.scale, value: '1', locked: true}
- {id: SCG.SOSCDIV1.scale, value: '1', locked: true}
- {id: SCG.SOSCDIV2.scale, value: '1', locked: true}
- {id: SCG.SPLLDIV1.scale, value: '2'}
- {id: SCG.SPLLDIV2.scale, value: '4', locked: true}
- {id: SCG.SPLL_mul.scale, value: '24', locked: true}
- {id: 'VLPR:SCG.DIVBUS.scale', value: '1', locked: true}
- {id: 'VLPR:SCG.DIVCORE.scale', value: '2', locked: true}
- {id: 'VLPR:SCG.DIVSLOW.scale', value: '4', locked: true}
- {id: 'VLPR:SCG.SCSSEL.sel', value: SCG.SIRC}
sources:
- {id: SCG.SOSC.outFreq, value: 16 MHz, enabled: true}
 * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/

/* *************************************************************************
* Configuration structure for peripheral clock configuration 0
* ************************************************************************* */
/*! @brief peripheral clock configuration 0 */
peripheral_clock_config_t peripheralClockConfig0[NUM_OF_PERIPHERAL_CLOCKS_0] = {
    {
        .clockName = ADC0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = ADC1_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPSPI0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPSPI1_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPSPI2_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPUART0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SOSC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPUART1_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SOSC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPUART2_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPI2C0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPIT0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = LPTMR0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FTM0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV1,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FTM1_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV1,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FTM2_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV1,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FTM3_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV1,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FLEXIO0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_SIRC_DIV2,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = CMP0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = CRC0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = DMAMUX0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = EWM0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FTFC0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PDB0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PDB1_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = RTC0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FlexCAN0_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FlexCAN1_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = FlexCAN2_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PORTA_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PORTB_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PORTC_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PORTD_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
    {
        .clockName = PORTE_CLK,
        .clkGate = true,
        .clkSrc = CLK_SRC_OFF,
        .frac = MULTIPLY_BY_ONE,
        .divider = DIVIDE_BY_ONE,
    },
};
/* *************************************************************************
* Configuration structure for Clock Configuration 0
* ************************************************************************* */
/*! @brief User Configuration structure clock_managerCfg_0 */
clock_manager_user_config_t clockMan1_InitConfig0 = {
    .scgConfig =
    {
        .sircConfig =
        {
            .initialize = true,
            .enableInStop = true,                 /* Enable SIRC in stop mode */
            .enableInLowPower = true,             /* Enable SIRC in low power mode */
            .locked = false,                      /* unlocked */
            .range = SCG_SIRC_RANGE_HIGH,         /* Slow IRC high range clock (8 MHz) */
            .div1 = SCG_ASYNC_CLOCK_DIV_BY_1,     /* Slow IRC Clock Divider 1: divided by 1 */
            .div2 = SCG_ASYNC_CLOCK_DIV_BY_1,     /* Slow IRC Clock Divider 3: divided by 1 */
        },
        .fircConfig =
        {
            .initialize = true,
            .regulator = true,                    /* FIRC regulator is enabled */
            .locked = false,                      /* unlocked */
            .range = SCG_FIRC_RANGE_48M,           /*!< RANGE      */
            .div1 = SCG_ASYNC_CLOCK_DIV_BY_1,     /* Fast IRC Clock Divider 1: divided by 1 */
            .div2 = SCG_ASYNC_CLOCK_DIV_BY_1,     /* Fast IRC Clock Divider 3: divided by 1 */
        },
        .rtcConfig =
        {
            .initialize = false,
        },
        .soscConfig =
        {
            .initialize = true,
            .freq = 16000000U,                    /* System Oscillator frequency: 16000000Hz */
            .monitorMode = SCG_SOSC_MONITOR_DISABLE,/* Monitor disabled */
            .locked = false,                      /* SOSC disabled */
            .extRef = SCG_SOSC_REF_OSC,           /* Internal oscillator of OSC requested. */
            .gain = SCG_SOSC_GAIN_LOW,            /* Configure crystal oscillator for low-gain operation */
            .range = SCG_SOSC_RANGE_HIGH,         /* High frequency range selected for the crystal oscillator of 8 MHz to 40 MHz. */
            .div1 = SCG_ASYNC_CLOCK_DIV_BY_1,     /* System OSC Clock Divider 1: divided by 1 */
            .div2 = SCG_ASYNC_CLOCK_DIV_BY_1,     /* System OSC Clock Divider 3: divided by 1 */
        },
        .spllConfig =
        {
            .initialize = true,
            .monitorMode = SCG_SPLL_MONITOR_DISABLE,/* Monitor disabled */
            .locked = false,                      /* unlocked */
            .prediv = (uint8_t)SCG_SPLL_CLOCK_PREDIV_BY_2,/* Divided by 2 */
            .mult = (uint8_t)SCG_SPLL_CLOCK_MULTIPLY_BY_24,/* Multiply Factor is 24 */
            .src = 0U,
            .div1 = SCG_ASYNC_CLOCK_DIV_BY_2,     /* System PLL Clock Divider 1: divided by 2 */
            .div2 = SCG_ASYNC_CLOCK_DIV_BY_4,     /* System PLL Clock Divider 3: divided by 4 */
        },
        .clockOutConfig =
        {
            .initialize = true,
            .source = SCG_CLOCKOUT_SRC_FIRC,      /* Fast IRC. */
        },
        .clockModeConfig =
        {
            .initialize = true,
            .rccrConfig =
            {
                .src = SCG_SYSTEM_CLOCK_SRC_SYS_PLL,/* System PLL */
                .divCore = SCG_SYSTEM_CLOCK_DIV_BY_6,/* Core Clock Divider: divided by 6 */
                .divBus = SCG_SYSTEM_CLOCK_DIV_BY_1,/* Bus Clock Divider: divided by 1 */
                .divSlow = SCG_SYSTEM_CLOCK_DIV_BY_2,/* Slow Clock Divider: divided by 2 */
            },
            .vccrConfig =
            {
                .src = SCG_SYSTEM_CLOCK_SRC_SIRC,/* Slow SIRC */
                .divCore = SCG_SYSTEM_CLOCK_DIV_BY_2,/* Core Clock Divider: divided by 2 */
                .divBus = SCG_SYSTEM_CLOCK_DIV_BY_1,/* Bus Clock Divider: divided by 1 */
                .divSlow = SCG_SYSTEM_CLOCK_DIV_BY_4,/* Slow Clock Divider: divided by 4 */
            },
            .hccrConfig =
            {
                .src = SCG_SYSTEM_CLOCK_SRC_SYS_PLL,/* System PLL */
                .divCore = SCG_SYSTEM_CLOCK_DIV_BY_3,/* Core Clock Divider: divided by 3 */
                .divBus = SCG_SYSTEM_CLOCK_DIV_BY_2,/* Bus Clock Divider: divided by 2 */
                .divSlow = SCG_SYSTEM_CLOCK_DIV_BY_4,/* Slow Clock Divider: divided by 4 */
            },
        },
    },
    .pccConfig =
    {
        .peripheralClocks = peripheralClockConfig0, /*!< Peripheral clock control configurations  */
        .count = NUM_OF_PERIPHERAL_CLOCKS_0, /*!< Number of the peripheral clock control configurations  */
    },
    .simConfig =
    {
        .clockOutConfig =
        {
            .initialize = true, /*!< Initialize    */
            .enable = true,                       /* enabled */
            .source = SIM_CLKOUT_SEL_SYSTEM_SCG_CLKOUT,/* SCG CLKOUT clock select: SCG slow clock */
            .divider = SIM_CLKOUT_DIV_BY_1,       /* Divided by 1 */
        },
        .lpoClockConfig =
        {
            .initialize = true, /*!< Initialize    */
            .enableLpo1k = true, /*!< LPO1KCLKEN    */
            .enableLpo32k = true, /*!< LPO32KCLKEN   */
            .sourceLpoClk = SIM_LPO_CLK_SEL_LPO_128K,/* 128 kHz LPO clock */
            .sourceRtcClk = SIM_RTCCLK_SEL_FIRCDIV1_CLK,/* FIRCDIV1 clock */
        },
        .platGateConfig =
        {
            .initialize = true, /*!< Initialize    */
            .enableEim = true, /*!< CGCEIM        */
            .enableErm = true, /*!< CGCERM        */
            .enableDma = true, /*!< CGCDMA        */
            .enableMpu = true, /*!< CGCMPU        */
            .enableMscm = true, /*!< CGCMSCM       */
        },
        .tclkConfig =
        {
            .initialize = false, /*!< Initialize    */
        },
        .traceClockConfig =
        {
            .initialize = true, /*!< Initialize    */
            .divEnable = true, /*!< TRACEDIVEN    */
            .source = CLOCK_TRACE_SRC_CORE_CLK, /*!< TRACECLK_SEL  */
            .divider = 0U, /*!< TRACEDIV      */
            .divFraction = false, /*!< TRACEFRAC     */
        },
    },
    .pmcConfig =
    {
        .lpoClockConfig =
        {
        .initialize = true,  /*!< Initialize    */
        .enable = true, /*!< Enable/disable LPO     */
        .trimValue = 0, /*!< Trimming value for LPO */
        },
    },
};

/*! @brief Array of pointers to User configuration structures */
clock_manager_user_config_t const * g_clockManConfigsArr[] = {
&clockMan1_InitConfig0
};

/*! @brief Array of pointers to User defined Callbacks configuration structures */
/* The tool do not support generate Callbacks configuration. It's always empty. */
clock_manager_callback_user_config_t * g_clockManCallbacksArr[] = {(void*)0};



				
			

Now, in this file all the initializations of the variables are done. As you change the configuration in S32 Clock Config tool, you can see change in values over here. 

Now the variables that are configured in  above .c/.h files are send to the functions of the Peripheral Abstraction Layer(Also called as Hardware Abstraction Layer). 

Peripheral Abstraction Layer Functions are directly used in main.c or application specific files. And internally Peripheral Abstraction Layer functions calls the low level functions which do the register level hardware changes on the corresponding S32K1 MCU.

Clock Peripheral Header and Source Files

S32 SDK driver provides an easy to use and quick way to use the Clock Peripheral in S32K144, using its Clock Manager driver Module.

Clock Manager Module SDK files for S32K144 MCU

Each S32 SDK driver can be configured and enabled to use in the project via S32 Configuration Tool. Will be digging into that part, in next section. For now, let’s understand the Clock Manager SDK in some detail, so as to use Clock  peripheral.

In the SDK of Clock Manager there are header and source files for Clock PAL( Peripheral Abstraction Layer) and Clock Low-Level Files:

  • Clock Low-Level Files: contains functions that configures the Clock Peripheral registers for initializing the peripheral, configuring the Peripheral and processing the data of peripheral at hardware level. These are the only ones which actually interacts with the hardware and make it configurable to our needs.
  • Clock Application/Peripheral Abstraction Layer(PAL): contains functions and variables that are directly used in main.c or application code. And internally these functions use the Clock Low-level Driver files.

So if hardware is changed out of any S32K1xx family of MCU’s, Clock peripheral would remain same and only internal low-level driver files needs to be changed or modified. By this way, we don’t have to make many changes on application level.

In the blogs we will be exploring the Clock Manager Peripheral Abstraction Layer files (PAL) in more details, as that would be directly used in our application project development(main.c) and doing custom Clock Configuration.

Clock Manager PAL

In CLOCK_CONFIG PAL there are 2 files CLOCK_S32K144.c and CLOCK_S32K144.h files.

Lets get into these files:

  1. CLOCK_S32K144.h: contains the enums, structures and function declarations that would be used in application code. Only functions which are declared in this header file can be used in main.c or application project.

  2. CLOCK_S32K144.c: contains the function definations of the declared functions(uses the low-level driver functions) along with some static functions also that are restricted to use in this file only.

Functions

  • CLOCK_DRV_Init: This function is the first function that has to be used in CLOCK_S32K144.h to initialize the clock in the MCU. 

				
					status_t CLOCK_DRV_Init(clock_manager_user_config_t const * config)


				
			
  • CLOCK_SYS_GetScgClockFreq :- this function is used to get the system clock frequency that is bydefault by the MCU.
				
					static status_t CLOCK_SYS_GetScgClockFreq(clock_names_t clockName,
                                          uint32_t * frequency);

				
			

Demo Code for Clock Peripheral

				
					/*

 * Copyright 2020 NXP
 * All rights reserved.
 *
 * NXP Confidential. This software is owned or controlled by NXP and may only be
 * used strictly in accordance with the applicable license terms. By expressly
 * accepting such terms or by downloading, installing, activating and/or otherwise
 * using the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms. If you do not agree to be
 * bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software. The production use license in
 * Section 2.3 is expressly granted for this software.
 */


#define EVB


#ifdef EVB
#define PCC_CLOCKPCC_PORTD_CLOCK
#define LED0_PORT PTD
#define LED0_PIN  15
#define LED1_PORT PTD
#define LED1_PIN  16
#else
#define PCC_CLOCKPCC_PORTC_CLOCK
#define LED0_PORT PTC
#define LED0_PIN  0
#define LED1_PORT PTC
#define LED1_PIN  1
#endif


#include "sdk_project_config.h"


void delay(volatile int cycles)
{
    /* Delay function - do nothing for a number of cycles */
    while(cycles--);
}
uint32_t frequency_bus_CLOCK;
uint32_t frequency_core_CLOCK;
uint32_t frequency_CLK_CLOCK;
uint32_t spll_CLOCK;
uint32_t sirc_CLOCK;
uint32_t firc_CLOCK;
uint32_t sosc_CLOCK;


int main(void)
{
  status_t error;
  /* Configure clocks for PORT */
  error = CLOCK_DRV_Init(&clockMan1_InitConfig0);
  DEV_ASSERT(error == STATUS_SUCCESS);
  /* Set pins as GPIO */
  error = PINS_DRV_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);
  DEV_ASSERT(error == STATUS_SUCCESS);


  /* Set Output value LED0 & LED1 */
  PINS_DRV_SetPins(LED0_PORT, 1 << LED0_PIN);
  PINS_DRV_ClearPins(LED1_PORT, 1 << LED1_PIN);


  for (;;)
  {
      /* Insert a small delay to make the blinking visible */
      delay(720000);


      /* Toggle output value LED0 & LED1 */
      PINS_DRV_TogglePins(LED0_PORT, 1 << LED0_PIN);
      PINS_DRV_TogglePins(LED1_PORT, 1 << LED1_PIN);


      (void)CLOCK_SYS_GetFreq(CORE_CLOCK, &frequency_core_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);


      (void)CLOCK_SYS_GetFreq(BUS_CLOCK, &frequency_bus_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);


      (void)CLOCK_SYS_GetFreq(CLKOUT_CLOCK, &frequency_CLK_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);


      (void)CLOCK_SYS_GetFreq(SIRC_CLOCK, &sirc_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);


      (void)CLOCK_SYS_GetFreq(FIRC_CLOCK, &firc_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);


      (void)CLOCK_SYS_GetFreq(SOSC_CLOCK, &sosc_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);


        (void)CLOCK_SYS_GetFreq(SPLL_CLOCK, &spll_CLOCK);
      /* Insert a small delay to make the blinking visible */
      delay(720000);
  }
}
				
			

Demo Code Description

Kunal Gupta
Author: Kunal Gupta

Author

Kunal Gupta

Leave a comment

Stay Updated With Us

Error: Contact form not found.

      Blog