Over 10 years we help companies reach their financial and branding goals. Engitech is a values-driven technology agency dedicated.

Gallery

Contacts

411 University St, Seattle, USA

engitech@oceanthemes.net

+1 -800-456-478-23

S32K144 Peripherals

GPIO Peripheral in S32K144 MCU

Table of Contents

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 first peripheral of this MCU. Going to Start with GPIO peripheral. Objective would be to get

  • familiarity with GPIO peripheral for S32K144 MCU.
  • Would be understanding GPIO peripheral from Hardware point of view in S32K144 MCU.
  • 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.

So read along the blog and do tell me its reviews!

GPIO Peripheral Theory

General Purpose Input/Output(GPIO) is a crucial peripheral in microcontrollers, enabling interaction with the external world by sending and receiving digital signals.

GPIO Crucial Peripheral in MCU’s

Digital Signals, here are referenced as High and Low Signals. High signal is +5/+3.3V level and Low Signal is 0V level. As MCU’s are digital devices, so it can only understand High and Low Voltage levels.

Digital Signals of GPIO

Almost all the pins of the Microcontroller are by default part of the GPIO peripheral, accept from the power pins. Every Pin can be configured in Input or Output State.

State of Pins

State of Pins
  • When a pin is configured as Input State, it can detect the level of external signal whether it is high signal or low signal. For example when we press the button, MCU process that as a external signal.
    GPIO as Input signal

Button is connected to one of the GPIO pins of the Microcontroller, which is being configured as Input state and when we press the button a High or Low voltage signal is generated. Which voltage level is generated? is detected by the configured GPIO Pin.

  • When a pin is configured as Output State, it can generate the High Signal or Low Signal to drive the external electronic devices. For example, LEDs are electronic devices which needs High signal to power-on them and low signal to power-off them.
    GPIO as Output signal

So LEDs are connected to one of the GPIO pins of the Microcontroller, which is being configured as Output State and then by programming we can configure the signal that has to be generated from the corresponding configured GPIO pin.

Input/output are defacto states of pins, apart from these 2 there are other states too, on which pins can be configured.

State of pins can be:

  • Output
  • Input
  • PullUp
  • PullDown
  • Tri-state

GPIO pins categorization

GPIO Ports and Pins

GPIOs are organized into banks, each requiring a unique identifier to identify a specific pin. These identifiers are commonly referred to as “Ports” and “Pads”. With the vast number of pins available on a microcontroller, it is essential to have a mechanism to reference and utilize them effectively.

To simplify this process, GPIO pins are now divided into Ports, with each Port containing a multiple of 8 pins. This division allows for easy referencing and addressing of the pins on the microcontroller.

By utilizing this system, developers can efficiently access and manipulate the GPIO pins on a microcontroller, streamlining the development process and improving overall functionality.

GPIO In S32K144 MCU

GPIO in S32K144

In S32K144 MCU, there are 5 ports of GPIO: named as PTA to PTE. Each Port pin has 16 pins.

In S32K144 reference manual, GPIO peripheral is being dicided into 2 modules: PORT (Port Control and Interrupt Module) and GPIO (General Purpose Input/Output Module).

PORT Module is responsible for Interrupt and Port Control Operations (Like alternate functions, Pull-up/down, drive strength) of the above Ports specified. GPIO module is responsible only for Controlling Input/Output directions of the port pins.

Features of GPIO in S32K144 MCU

  • Pins can be configured as Output.
  • Pins can be configured as Input.
  • Pins support the multiplexing of signals, so that a single pin can be do different job(refer to signal multiplexing section).
  • Dedicated Port Output registers for set/clear/toggle the bits.
  • Efficient bit manipulation of the general-purpose outputs is supported through the addition of set, clear, and toggle write-only registers for each port output data register.
  • GPIO module can operate on 3 modes: Run Mode, Stop Mode and Debug Mode
  • GPIO Module is clocked by System clock.
  • GPIO module has a feature of Lock feature, in this feature we can lock the Mode of operation of PIN in one Power Cycle. 

Registers of GPIO in S32K144

For simplicity, each GPIO port’s register appear with the same width of 32 bits, corresponding to 32 pins. The actual number of pins per port in S32K144 is 16 pins. So we will be addressing only first 16 bits of the registers, on last remaining 16 bits are irrelevant for us. But in S32K144 there are 16 pins only per port, so we will be accessing only first 16 bits of the registers (0-15), reading & writing on (16-31) will have no effect.

In S32K144, there are registers to support 8bit, 16-bit and 32-bit access. Registers of GPIO:

  • GPIO Data Direction register: Direction of GPIO pin
  • GPIO output data register: Output direction of GPIO pin
  • GPIO Input Data Register: Displays the logic value on each pin

Efficient bit manipulation of the general-purpose outputs is supported through the addition of set, clear, and toggle write-only registers for each port output data register.

Each Port of GPIO has 16 pins. And each pin is referenced as each bit of the above registers.

Features of Pin configured as Output:

Output: Pin is configured for the GPIO Function and corresponding port data direction register bit is set.

 For efficient bit manipulation, there are dedicated output registers for toggling, Set High or Set LOW the pins. Instead of doing the manipulation of pin signals via software using bit manipulation and shifting

Features of Pin Configured as Input

Input: If Pin is configured for the GPIO function and the corresponding port data direction register bit is clear.

GPIO Hardware/Pinout in S32K144 MCU

S32K144 MCU comes in 3 pin counts: S32K144_100lqfp, S32K144_64lqfp, S32K144_48lqfp. The one which we will be using is S32K144_100lqfp. S32K144 EVB board which is explained in last blog, has S32K144 MCU of S32K144_100lqfp packaging. 

S32K144 EVB Board and Chip

For GPIO peripheral to use, in terms of Hardware first thing that is needed is pinout of the MCU.

To see the pinout of S32K144 MCU, you will not find that on its Datasheet or Reference Manual. But there is separate excel sheets to know details for its pinout, by the name of: S32K144_IO_Signal_Description_Input_Multiplexing.excel.

This excel is attached with S32K144 MCU reference manual. Open the Reference Manual of S32K144 with Adobe Acrobat and click on below highlighted icon. 

S32K1 Reference Manual Getting Started
S32K144 Pinout Excel

Now coming back to pinout of S32K144 MCU, this below is the pinout that is extracted from the excel sheet for the S32K144_100lqfp packaging. We would be referring this packaging only throughout the series,

S32K144_100lqfp_packaging_pinout

One can see, that their are 100 pins in this MCU S32K144. Starting from pin 1 which belongs to PTE16 and pin 100 which belongs to PTA8.

As you can see there are so many, to use them we need to have some kind of referencing. Thus, concept of Ports is there. Their are total 5 Ports in S32K144 MCU and supply pins: 

  • PTA: PTA0-PTA17(18 pins)
  • PTB: PTB0-PTB17(18 pins)
  • PTC: PTC0-PTC17(18 pins)
  • PTD: PTD0-PTD17(18 pins)
  • PTE: PTE0-PTE16(17 pins)
  • And 11 Supply pins (VDD, VDDA, VREFH, VREFL, VSS)

Now in the excel sheet one can find that there are multiple sheets as follows.

Also in S32 Configuration Tool in S32 Design Studio one can see all the details of the MCU Pinout and description.( Will be telling more on S32 Configuration and S32 DS later.)

S32 Pinout in S32 Configuration Tool via S32 Design Studio

Now in S32K144 EVB Board, pin numbering is done in bit different way. Pin Naming is not done directly by the name of Pins name as referenced in Pinout Sheet. Instead, it is done in terms of Jacks. As shown in below pic.

S32K144_EVB_Board_Pinout

There are 6 Jack Connectors: J1-J6. All Jack are of Female Connectors(This might make the connections messy).  J1 & J3 have 16 pin count. J5, J6 & J7 have 20 pin count. J4 have 15 There are. From the above pic you can refer out the Pin name of each Jack Pin. And then correspondingly get to know about that Pin via Sheet.

How to use the GPIO Peripheral in S32K144 MCU

So as to know about S32 configuration tool and how to configure/use the GPIO peripheral in S32K144 MCU, refer to this video.

GPIO SDK for S32K144 MCU

S32 SDK/ drivers provide an easy to use and quick way to use the GPIO peripheral in S32K144, which is known as Pin Driver.

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 Pin driver in more details, so as to use the GPIO periperal.

Broadly there are 5 files in Pin Driver, that controls the GPIO peripheral in S32K144 MCU:

  • pins_driver.h
  • pins_driver.c
  • pins_gpio_hw_access.h
  • pins_port_hw_access.h
  • pins_port_hw_access.c

pins_driver.h & pins_driver.c are the GPIO Peripheral Abstraction Layer and Rest 3 are the GPIO low-level drivers of the GPIO peripherals.

GPIO Peripheral Abstraction layer functions are the ones that are directly used in main.c or Application code. And internally these functions use the GPIO low-level driver functions.

Thus, we would find that in Rest 3 files, most of the functions are static functions and static inline functions, as low-level driver functions are internally used in Peripheral Abstraction Layer functions. So that if hardware is changed, so only low-level driver functions would be changed. GPIO PAL functions would remain same and their would be very small amount of change required in Application code or main.c. This is how Code Portability and modularity is designed, providing efficient use.

Configuring GPIO Pins

First thing, that we need to do for using GPIO pins, is to configure them. By configure we mean:

  • Which pin to use and that pin belongs to which port.
  • pin to be used in what state or if pin to be used by other peripheral then configuring the state of pin according to that(pin multiplexing)
  • to configure the features, like pullup/down resistors, slew rate, open drain, over current and etc( this is kind of chip specific, according to the chip their are different features)

To configure the GPIO pins, in pins_driver.h there is a structure pin_settings_config_t. This structure allows users to properly exploit S32K1 GPIO features.

				
					
/*!
 * @brief Defines the converter configuration
 *
 * This structure is used to configure the pins
 * Implements : pin_settings_config_t_Class
 */

typedef struct
{
#ifdef FEATURE_PINS_DRIVER_USING_PORT
    PORT_Type         *         base;              /*!< Port base pointer.                        */
#elif defined FEATURE_PINS_DRIVER_USING_SIUL2
    SIUL2_Type        *         base;              /*!< SIUL2 base pointer.                       */
#endif
    uint32_t                    pinPortIdx;        /*!< Port pin number.                          */
#if FEATURE_PINS_HAS_PULL_SELECTION
    port_pull_config_t          pullConfig;        /*!< Internal resistor pull feature selection. */
#endif
#if FEATURE_PINS_HAS_SLEW_RATE
    port_slew_rate_t            rateSelect;        /*!< Slew rate selection.                      */
#endif
#if FEATURE_PORT_HAS_PASSIVE_FILTER
    bool                        passiveFilter;     /*!< Passive filter configuration.             */
#endif
#if FEATURE_PINS_HAS_OPEN_DRAIN
    port_open_drain_t           openDrain;         /*!< Configures open drain.                    */
#endif
#if FEATURE_PINS_HAS_DRIVE_STRENGTH
    port_drive_strength_t       driveSelect;       /*!< @brief Configures the drive strength.     */
#endif
    port_mux_t                  mux;               /*!< @brief Pin (C55: Out) mux selection.      */
#if FEATURE_PORT_HAS_PIN_CONTROL_LOCK
    bool                        pinLock;           /*!< Lock pin control register or not.         */
#endif
#ifdef FEATURE_PINS_DRIVER_USING_PORT
    port_interrupt_config_t     intConfig;         /*!< Interrupt generation condition.           */
    bool                        clearIntFlag;      /*!< Clears the interrupt status flag.         */
    bool                        digitalFilter;     /*!< Enables digital filter.                   */
#if FEATURE_PINS_HAS_OVER_CURRENT
    bool                        clearOCurFlag;     /*!< Clears the Over-Current status flag.      */
    port_over_current_config_t  overCurConfig;     /*!< Over-current detection feature.           */
#endif
#endif
    GPIO_Type         *         gpioBase;          /*!< GPIO base pointer.                        */
    port_data_direction_t       direction;         /*!< Configures the port data direction.       */
#ifdef FEATURE_PINS_DRIVER_USING_SIUL2
    port_input_mux_t    inputMux[FEATURE_SIUL2_INPUT_MUX_WIDTH];   /*!< Configures the input muxing selection */
#if FEATURE_SIUL2_HAS_INVERT_DATA_INPUT
    port_invert_input_t inputInvert[FEATURE_SIUL2_INPUT_MUX_WIDTH];/*!< Configures the Invert Data Input.     */
#endif /* FEATURE_SIUL2_HAS_INVERT_DATA_INPUT */
    uint32_t            inputMuxReg[FEATURE_SIUL2_INPUT_MUX_WIDTH];/*!< Configures the input muxing register  */
    port_output_buffer_t        outputBuffer;      /*!< Configures the Output Buffer Enable.      */
    port_input_buffer_t         inputBuffer;       /*!< Configures the Input Buffer Enable.       */
    siul2_interrupt_config_t    intConfig;         /*!< Interrupt generation condition.           */
#if FEATURE_SIUL2_HAS_SAFE_MODE_CONTROL
    port_safe_mode_t            safeMode;          /*!< Configures the Safe Mode Control.         */
#endif /* FEATURE_SIUL2_HAS_SAFE_MODE_CONTROL */
#if FEATURE_SIUL2_HAS_SLEW_RATE_CONTROL
    port_slew_rate_control_t    slewRateCtrlSel;   /*!< Configures the Slew Rate Control field.   */
#endif /* FEATURE_SIUL2_HAS_SLEW_RATE_CONTROL */
#if FEATURE_SIUL2_HAS_HYSTERESIS
    port_hysteresis_t           hysteresisSelect;  /*!< Configures the Hysteresis Enable.         */
#endif /* FEATURE_SIUL2_HAS_HYSTERESIS */
#if FEATURE_SIUL2_HAS_DDR_PAD
    pin_ddr_config_t            ddrConfiguration;  /*!< Structure that configures the DDR         */
    port_ddr_input_t            inputMode;         /*!< Configures DDR input receiver mode.       */
    port_on_die_termination_t   odtSelect;         /*!< Configures the ODT to select strength.    */
#endif /* FEATURE_SIUL2_HAS_DDR_PAD */
#if FEATURE_SIUL2_HAS_INVERT_DATA_OUTPUT
    port_invert_output_t        invertOutput;      /*!< Configures the Invert Data Output.        */
#endif /* FEATURE_SIUL2_HAS_INVERT_DATA_OUTPUT */
#if FEATURE_SIUL2_HAS_PULL_KEEPER
    port_pull_keep_t            pullKeepEnable;    /*!< Configures the Pull / Keep Enable.        */
    port_pull_keeper_select_t   pullKeepSelect;    /*!< Configures the Pull / Keep Select.        */
    port_pull_up_down_t         pullSelect;        /*!< Configures the Pull Up / Down Config.     */
#endif /* FEATURE_SIUL2_HAS_PULL_KEEPER */
#if FEATURE_SIUL2_HAS_ANALOG_PAD
    port_analog_pad_t           analogPadCtrlSel;  /*!< Configures the Analog Pad Control         */
#endif /* FEATURE_SIUL2_HAS_ANALOG_PAD */
#endif /* FEATURE_PINS_DRIVER_USING_SIUL2 */
    pins_level_type_t           initValue;         /*!< Initial value                             */
} pin_settings_config_t;

				
			

You can see in the structure that members of the structure have been created according to the Macros that are defined. Each Macro enables or disables the feature or configuration type. The members of the structure denote the different features of GPIO Peripheral and Configuration of GPIO hardware registers and in some cases also the callback functions.

Macros have been named, so that on reading them one can understand what features or configurations that Macro would be controlling.

Now these Macros are defined in S32K144_features.h file. Every S32K MCU would be having different features so correspondingly members of the structures would be created. The Macros which have assigned 1 value, those are features supported in S32K144 MCU and correspondingly its members would be created in structure. Macros which have assigned 0 value, those features are supported in that MCU.

				
					
/*!
 * @file S32K144_features.h
 * @brief Chip specific module features
 * PORT module features */
 *! @brief PORT Used for setting Pins 
 */
#define FEATURE_PINS_DRIVER_USING_PORT (1)
/* @brief Has control lock (register bit PCR[LK]). */
#define FEATURE_PORT_HAS_PIN_CONTROL_LOCK (1)
/* @brief Has open drain control (register bit PCR[ODE]). */
#define FEATURE_PINS_HAS_OPEN_DRAIN (0)
/* @brief Has digital filter (registers DFER, DFCR and DFWR). */
#define FEATURE_PORT_HAS_DIGITAL_FILTER (1)
/* @brief Has trigger output to trigger other peripherals (register bit field PCR[IRQC] values). */
#define FEATURE_PORT_HAS_TRIGGER_OUT (0)
/* @brief Has setting flag only (register bit field PCR[IRQC] values). */
#define FEATURE_PORT_HAS_FLAG_SET_ONLY (0)
/* @brief Has over-current feature (register bit field PCR[OCIE] values). */
#define FEATURE_PINS_HAS_OVER_CURRENT (0)
/* @brief Has pull resistor selection available. */
#define FEATURE_PINS_HAS_PULL_SELECTION (1)
/* @brief Has slew rate control (register bit PCR[SRE]). */
#define FEATURE_PINS_HAS_SLEW_RATE (0)
/* @brief Has passive filter (register bit field PCR[PFE]). */
#define FEATURE_PORT_HAS_PASSIVE_FILTER (1)
/* @brief Has drive strength (register bit PCR[DSE]). */
#define FEATURE_PINS_HAS_DRIVE_STRENGTH (1)
/* @brief Has drive strength control bits*/
#define FEATURE_PINS_HAS_DRIVE_STRENGTH_CONTROL (0)
/* @brief Has port input disable control bits*/
#define FEATURE_PORT_HAS_INPUT_DISABLE (1)
/* @brief SIM_CHIPCTL_ADC_INTERLEAVE_EN bit is available */
#define FEATURE_PINS_HAS_ADC_INTERLEAVE_EN (1)


				
			

So for S32K144, if we see following structure members would be created:

				
					typedef struct
{
#ifdef FEATURE_PINS_DRIVER_USING_PORT
    PORT_Type         *         base;              /*!< Port base pointer.                        */
#endif
    uint32_t                    pinPortIdx;        /*!< Port pin number.                          */
#if FEATURE_PINS_HAS_PULL_SELECTION
    port_pull_config_t          pullConfig;        /*!< Internal resistor pull feature selection. */
#endif
#endif
#if FEATURE_PORT_HAS_PASSIVE_FILTER
    bool                        passiveFilter;     /*!< Passive filter configuration.             */
#endif
#if FEATURE_PINS_HAS_DRIVE_STRENGTH
    port_drive_strength_t       driveSelect;       /*!< @brief Configures the drive strength.     */
#endif
    port_mux_t                  mux;               /*!< @brief Pin (C55: Out) mux selection.      */
#if FEATURE_PORT_HAS_PIN_CONTROL_LOCK
    bool                        pinLock;           /*!< Lock pin control register or not.         */
#endif
#ifdef FEATURE_PINS_DRIVER_USING_PORT
    port_interrupt_config_t     intConfig;         /*!< Interrupt generation condition.           */
    bool                        clearIntFlag;      /*!< Clears the interrupt status flag.         */
    bool                        digitalFilter;     /*!< Enables digital filter.                   */
#endif
    GPIO_Type         *         gpioBase;          /*!< GPIO base pointer.                        */
    port_data_direction_t       direction;         /*!< Configures the port data direction.       */
    pins_level_type_t           initValue;         /*!< Initial value                             */
} pin_settings_config_t;

				
			

Now structure members in pin_settings_config_t have been created using users defined data types. These user defined data types are basically, typedef enumerations or structures. These typedef enumerations are further used at the time of initializing this structure to configure GPIO pins.

Why do you think in structure such an user defined data types are used?Tell in below comment section

				
					
/*******************************************************************************
 * Definitions
 ******************************************************************************/
#if defined(FEATURE_PINS_DRIVER_USING_PORT)
/*!
 * @brief Type of a GPIO channel representation
 * Implements : pins_channel_type_t_Class
 */
typedef uint32_t pins_channel_type_t;

#elif defined(FEATURE_PINS_DRIVER_USING_SIUL2)
/*!
 * @brief Type of a GPIO channel representation
 * Implements : pins_channel_type_t_Class
 */
typedef uint16_t pins_channel_type_t;

#endif /* if defined(FEATURE_PINS_DRIVER_USING_PORT) */

/*!
 * @brief Type of a port levels representation.
 * Implements : pins_level_type_t_Class
 */
typedef uint8_t pins_level_type_t;

/*!
 * @brief Configures the port data direction
 * Implements : port_data_direction_t_Class
 */
typedef enum
{
    GPIO_INPUT_DIRECTION       = 0x0U,  /*!< General purpose input direction.       */
    GPIO_OUTPUT_DIRECTION      = 0x1U,  /*!< General purpose output direction.      */
    GPIO_UNSPECIFIED_DIRECTION = 0x2U   /*!< General purpose unspecified direction. */
} port_data_direction_t;

#if FEATURE_PINS_HAS_PULL_SELECTION
/*!
 * @brief Internal resistor pull feature selection
 * Implements : port_pull_config_t_Class
 */
typedef enum
{
    PORT_INTERNAL_PULL_NOT_ENABLED   = 0U,  /*!< internal pull-down or pull-up resistor is not enabled.           */
    PORT_INTERNAL_PULL_DOWN_ENABLED  = 1U,  /*!< internal pull-down resistor is enabled. @internal gui name="Down"*/
    PORT_INTERNAL_PULL_UP_ENABLED    = 2U   /*!< internal pull-up resistor is enabled. @internal gui name="Up"    */
} port_pull_config_t;
#endif /* FEATURE_PINS_HAS_PULL_SELECTION */

#if FEATURE_PINS_HAS_OPEN_DRAIN
/*!
 * @brief Configures the Open Drain Enable field.
 * Implements : port_open_drain_t_Class
 */
typedef enum
{
    PORT_OPEN_DRAIN_DISABLED  = 0U, /*!< Output is CMOS       */
    PORT_OPEN_DRAIN_ENABLED   = 1U  /*!< Output is open drain */
} port_open_drain_t;
#endif /* FEATURE_PINS_HAS_OPEN_DRAIN */

#if FEATURE_PINS_HAS_DRIVE_STRENGTH
/*!
 * @brief Configures the drive strength.
 * Implements : port_drive_strength_t_Class
 */
typedef enum
{
#if FEATURE_PINS_HAS_DRIVE_STRENGTH_CONTROL
    PORT_STRENGTH_DISABLED      = 0U, /*!< Output driver disabled                                         */
    PORT_LOW_DRIVE_STRENGTH     = 1U, /*!< Low drive strength is configured. Resistor is set to 240 Ohm   */
    PORT_STR1_DRIVE_STRENGTH    = 1U, /*!< Resistor is set to 240 Ohm                                     */
    PORT_STR2_DRIVE_STRENGTH    = 2U, /*!< Resistor is set to 240 / 2 Ohm = 120 Ohm                       */
    PORT_STR3_DRIVE_STRENGTH    = 3U, /*!< Resistor is set to 240 / 3 Ohm = 80 Ohm                        */
    PORT_STR4_DRIVE_STRENGTH    = 4U, /*!< Resistor is set to 240 / 4 Ohm = 60 Ohm                        */
    PORT_STR5_DRIVE_STRENGTH    = 5U, /*!< Resistor is set to 240 / 5 Ohm = 48 Ohm                        */
    PORT_STR6_DRIVE_STRENGTH    = 6U, /*!< Resistor is set to 240 / 6 Ohm = 40 Ohm                        */
    PORT_STR7_DRIVE_STRENGTH    = 7U, /*!< Resistor is set to 240 / 7 Ohm = 34 Ohm                        */
    PORT_HIGH_DRIVE_STRENGTH    = 7U  /*!< High drive strength is configured. Resistor is set to 240 Ohm  */
#else /* if not FEATURE_PINS_HAS_DRIVE_STRENGTH_CONTROL */
    PORT_LOW_DRIVE_STRENGTH     = 0U,    /*!< low drive strength is configured. @internal gui name="Low"  */
    PORT_HIGH_DRIVE_STRENGTH    = 1U     /*!< high drive strength is configured. @internal gui name="High"*/
#endif /* if FEATURE_PINS_HAS_DRIVE_STRENGTH_CONTROL */
} port_drive_strength_t;
#endif /* FEATURE_PINS_HAS_DRIVE_STRENGTH */

#ifdef FEATURE_PINS_DRIVER_USING_PORT
/*!
 * @brief Configures the Pin mux selection
 * Implements : port_mux_t_Class
 */
typedef enum
{
    PORT_PIN_DISABLED            = 0U,  /*!< corresponding pin is disabled, but is used as an analog pin       */
    PORT_MUX_AS_GPIO             = 1U,  /*!< corresponding pin is configured as GPIO                           */
    PORT_MUX_ALT2                = 2U,  /*!< chip-specific                                                     */
    PORT_MUX_ALT3                = 3U,  /*!< chip-specific                                                     */
    PORT_MUX_ALT4                = 4U,  /*!< chip-specific                                                     */
    PORT_MUX_ALT5                = 5U,  /*!< chip-specific                                                     */
    PORT_MUX_ALT6                = 6U,  /*!< chip-specific                                                     */
    PORT_MUX_ALT7                = 7U,  /*!< chip-specific                                                     */
#if FEATURE_PINS_HAS_ADC_INTERLEAVE_EN
    PORT_MUX_ADC_INTERLEAVE      = 8U   /*!< when selected, ADC Interleaved channel is connected to current pin
                                         *   and disconnected to opposed pin
                                         * ADC1_SE14-PTB15 | ADC1_SE15-PTB16 | ADC0_SE8-PTC0  | ADC0_SE9-PTC1
                                         * ADC1_SE14-PTB0  | ADC1_SE15-PTB1  | ADC0_SE8-PTB13 | ADC0_SE9-PTB14 */
#endif /* FEATURE_PINS_HAS_ADC_INTERLEAVE_EN */
} port_mux_t;

/*!
 * @brief Configures the interrupt generation condition.
 * Implements : port_interrupt_config_t_Class
 */
typedef enum
{
    PORT_DMA_INT_DISABLED  = 0x0U,  /*!< Interrupt/DMA request is disabled.                   */
    PORT_DMA_RISING_EDGE   = 0x1U,  /*!< DMA request on rising edge.                          */
    PORT_DMA_FALLING_EDGE  = 0x2U,  /*!< DMA request on falling edge.                         */
    PORT_DMA_EITHER_EDGE   = 0x3U,  /*!< DMA request on either edge.                          */
#if FEATURE_PORT_HAS_FLAG_SET_ONLY
    PORT_FLAG_RISING_EDGE  = 0x5U,  /*!< Flag sets on rising edge, no interrupt is generated. */
    PORT_FLAG_FALLING_EDGE = 0x6U,  /*!< Flag sets on falling edge, no interrupt is generated.*/
    PORT_FLAG_EITHER_EDGE  = 0x7U,  /*!< Flag sets on either edge, no interrupt is generated. */
#endif /* FEATURE_PORT_HAS_FLAG_SET_ONLY */
    PORT_INT_LOGIC_ZERO    = 0x8U,  /*!< Interrupt when logic 0.                              */
    PORT_INT_RISING_EDGE   = 0x9U,  /*!< Interrupt on rising edge.                            */
    PORT_INT_FALLING_EDGE  = 0xAU,  /*!< Interrupt on falling edge.                           */
    PORT_INT_EITHER_EDGE   = 0xBU,  /*!< Interrupt on either edge.                            */
    PORT_INT_LOGIC_ONE     = 0xCU,  /*!< Interrupt when logic 1.                              */
#if FEATURE_PORT_HAS_TRIGGER_OUT
    PORT_HIGH_TRIGGER_OUT  = 0xDU,  /*!< Enable active high trigger output, flag is disabled. */
    PORT_LOW_TRIGGER_OUT   = 0xEU   /*!< Enable active low trigger output, flag is disabled.  */
#endif /* FEATURE_PORT_HAS_TRIGGER_OUT */
} port_interrupt_config_t;

#if FEATURE_PINS_HAS_SLEW_RATE
/*!
 * @brief Configures the Slew Rate field.
 * Implements : port_slew_rate_t_Class
 */
typedef enum
{
    PORT_FAST_SLEW_RATE     = 0U,   /*!< fast slew rate is configured. @internal gui name="Fast" */
    PORT_SLOW_SLEW_RATE     = 1U    /*!< slow slew rate is configured. @internal gui name="Slow" */
} port_slew_rate_t;
#endif /* FEATURE_PINS_HAS_SLEW_RATE */

/*!
 * @brief Clock source for the digital input filters
 * Implements : port_digital_filter_clock_t_Class
 */
typedef enum
{
    PORT_DIGITAL_FILTER_BUS_CLOCK  = 0U, /*!< Digital filters are clocked by the bus clock. @internal gui name="BUS" */
    PORT_DIGITAL_FILTER_LPO_CLOCK  = 1U  /*!< Digital filters are clocked by the LPO clock. @internal gui name="LPO" */
} port_digital_filter_clock_t;

/*!
 * @brief The digital filter configuration
 * Implements : port_digital_filter_config_t_Class
 */
typedef struct
{
    port_digital_filter_clock_t clock;  /*!< The digital filter clock for port */
    uint8_t                     width;  /*!< The digital filter width value */
} port_digital_filter_config_t;

/*!
 * @brief The port global pin/interuppt control registers
 * Implements : port_global_control_pins_t_Class
 */
typedef enum
{
    PORT_GLOBAL_CONTROL_LOWER_HALF_PINS = 0U, /*!< the lower of pins is configured. @internal gui name="Lower" */
    PORT_GLOBAL_CONTROL_UPPER_HALF_PINS = 1U  /*!< the upper of pins is configured. @internal gui name="Upper" */
} port_global_control_pins_t;

				
			

Initialising GPIO Pins

Now to configure the GPIO pins, let’s look at some examples on how this structure is been initialized.  Now lets say we have to use pin number J4-11 as Output pin 

Here we have created the structure variable for pin_settings_config_t structure as g_pin_InitConfig.

				
					  /* Generate array of configured pin structures */
  
  #define NUM_OF_CONFIGURED_PINS0 1
  pin_settings_config_t g_pin_mux_InitConfigArr0[NUM_OF_CONFIGURED_PINS0] =
    {
        .base            = PORTC,
        .pinPortIdx      = 0U,
        .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
        .driveSelect     = PORT_LOW_DRIVE_STRENGTH,
        .passiveFilter   = false,
        .mux             = PORT_MUX_AS_GPIO,
        .pinLock         = false,
        .intConfig       = PORT_DMA_INT_DISABLED,
        .clearIntFlag    = false,
        .gpioBase        = PTC,
        .direction       = GPIO_OUTPUT_DIRECTION,
        .digitalFilter   = false,
        .initValue       = 0U,
    };
				
			
  • Pin number J4-11 is PTC0 pin, so its Port is PORTC and Port pin number is 0.
  • Further no internal pull-up resistor feature is used so member pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED.
  • DriveSelect for the pin is Low by default, that also has to be set as driveSelect = PORT_LOW_DRIVE_STRENGTH.
  • No Passive filter is used, by default so passiveFilter = false.
  • Pin is to be used as normal GPIO pin, so its mux =  PORT_MUX_AS_GPIO
  • pin locking is not to be used by default it would also be pinLock= False
  • Interrupts and DMA are not used, so intConfig = PORT_DMA_INT_DISABLED.
  • GPIO Base is PTC. So gpioBase=PTC.
  • data direction for the pin is Output direction. So direction= GPIO_OUTPUT_DIRECTION.
  • digital filter feature is also not used by default so that is set to digitalFilter = false.
  • initialValue of pin is set to Low signal. That is initValue= 0.

Now this structure is passed on to the function PINS_DRV_Init(), to initialze the hardware registers according to our configuration of GPIO pins.

				
					/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_DRV_Init
 * Description   : This function configures the pins with the options provided
 * in the given structure.
 *
 * Implements    : PINS_DRV_Init_Activity
 *END**************************************************************************/
status_t PINS_DRV_Init(uint32_t pinCount,
                       const pin_settings_config_t config[])
{
    uint32_t i;
    for (i = 0U; i < pinCount; i++)
    {
        PINS_Init(&config[i]);
    }

    return STATUS_SUCCESS;
}

				
			
				
					PINS_DRV_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);
  
				
			

GPIO Operations

Output State

NXP S32SDK provides mixture of functions to play with. Like if pin is configured as Output state, then it can be set to high value or Low value using.

  • PINS_DRV_SetPins (). This function configures output pins listed in parameter pins (bits that are
     ‘1’) to have a value of ‘set’ (HIGH). Pins corresponding to ‘0’ will be
    unaffected.
				
					/*FUNCTION***************************************************
 *
 * Function Name : PINS_DRV_SetPins
 * Description   : This function configures output pins listed in parameter pins (bits that are
 * '1') to have a value of 'set' (HIGH). Pins corresponding to '0' will be
 * unaffected.
 *
 * Implements    : PINS_DRV_SetPins_Activity
 *END*****************************************************/
void PINS_DRV_SetPins(GPIO_Type * const base,
                      pins_channel_type_t pins)
{
    PINS_GPIO_SetPins(base, pins);
}

				
			
				
						#define LED0_PORT PTC
#define LED0_PIN  0
PINS_DRV_SetPins(LED0_PORT, 1 << LED0_PIN);
  
				
			
  • PINS_DRV_ClearPins(): This function configures output pins listed in parameter pins (bits that are ‘1’) to have a ‘cleared’ value (LOW). Pins corresponding to ‘0’ will be unaffected.
				
					/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_DRV_ClearPins
 * Description   : This function configures output pins listed in parameter pins (bits that are
 * '1') to have a 'cleared' value (LOW). Pins corresponding to '0' will be
 * unaffected.
 *
 * Implements    : PINS_DRV_ClearPins_Activity
 *END**************************************************************************/
void PINS_DRV_ClearPins(GPIO_Type * const base,
                        pins_channel_type_t pins)
{
    PINS_GPIO_ClearPins(base, pins);
}

				
			
				
						#define LED0_PORT PTC
#define LED0_PIN  0
PINS_DRV_ClearPins(LED0_PORT, 1 << LED0_PIN);
  
				
			
  • PINS_DRV_WritePin(): This function writes the given pin from a port with the given value ( ‘0’ represents LOW, ‘1’ represents HIGH).
				
					/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_DRV_WritePin
 * Description   : This function writes the given pin from a port, with the given value
 * ('0' represents LOW, '1' represents HIGH).
 *
 * Implements    : PINS_DRV_WritePin_Activity
 *END**************************************************************************/
void PINS_DRV_WritePin(GPIO_Type * const base,
                       pins_channel_type_t pin,
                       pins_level_type_t value)
{
    PINS_GPIO_WritePin(base, pin, value);
}

				
			
				
						#define LED0_PORT PTC
#define LED0_PIN  0
PINS_DRV_WritePin(LED0_PORT, LED0_PIN, 1); // Set Pin as High
PINS_DRV_WritePin(LED0_PORT, LED0_PIN, 0); // Set Pin as Low

				
			
  • PINS_DRV_WritePins(): This function writes all pins configured as output with the values given in the parameter pins. ‘0’ represents LOW, ‘1’ represents HIGH.
				
					/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_DRV_WritePins
 * Description   : This function writes all pins configured as output with the values given in
 * the parameter pins. '0' represents LOW, '1' represents HIGH.
 *
 * Implements    : PINS_DRV_WritePins_Activity
 *END**************************************************************************/
void PINS_DRV_WritePins(GPIO_Type * const base,
                        pins_channel_type_t pins)
{
    PINS_GPIO_WritePins(base, pins);
}

				
			
				
						#define LED0_PORT PTC
#define LED0_PIN  0
PINS_DRV_WritePins(LED0_PORT, 2 << LED0_PIN); //0b00000010
				
			
  • PINS_DRV_TogglePins(): This function toggles output pins listed in parameter pins (bits that are ‘1’). Pins corresponding to ‘0’ will be unaffected.
				
					/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_DRV_TogglePins
 * Description   : This function toggles output pins listed in parameter pins (bits that are
 * '1'). Pins corresponding to '0' will be unaffected.
 *
 * Implements    : PINS_DRV_TogglePins_Activity
 *END**************************************************************************/
void PINS_DRV_TogglePins(GPIO_Type * const base,
                         pins_channel_type_t pins)
{
    PINS_GPIO_TogglePins(base, pins);
}

				
			
				
						#define LED0_PORT PTC
#define LED0_PIN  0
PINS_DRV_TogglePins(LED0_PORT, 1 << LED0_PIN); //0b00000001
				
			

Input State

NXP S32 SDK Provide following functions to play with, if pin is configured as input state. 

  • PINS_DRV_ReadPins(): This function returns the current input values from a port. Only pins configured as input will have meaningful values.
				
					/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_DRV_ReadPins
 * Description   : This function returns the current input values from a port. Only pins
 * configured as input will have meaningful values.
 *
 * Implements    : PINS_DRV_ReadPins_Activity
 *END**************************************************************************/
pins_channel_type_t PINS_DRV_ReadPins(const GPIO_Type * const base)
{
    return PINS_GPIO_ReadPins(base);
}

				
			
				
						#define LED0_PORT PTC
pins_channel_type_t x = 
PINS_DRV_ReadPins(LED0_PORT);

				
			

GPIO Demo code in S32K144 MCU

				
					/*
 * 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

	#define PCC_CLOCK	PCC_PORTC_CLOCK
	#define LED0_PORT PTC
	#define LED0_PIN  0
	#define LED1_PORT PTC
	#define LED1_PIN  1

#include "sdk_project_config.h"

void delay(volatile int cycles)
{
    /* Delay function - do nothing for a number of cycles */
    while(cycles--);
}

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);
  }
}

				
			

Tigger MUX Control(TRGMUX) Peripheral in S32K144 MCU

What is TRGMUX peripheral? TRGMUC provides an extremely flexible mechanism for connecting various trigger sources to multiple pins/peripherals. The trigger multiplexer (TRGMUX) module allows software to configure the trigger inputs for various peripherals.   The TRGMUX module allows software to select the trigger source for peripherals.   TRGMUX is a peripheral which provides mechanisms for connecting various trigger sources to multiple pins/peripherals. Each peripheral that accepts external triggers usually has one specific 32-bit trigger control register. Each control register supports upto 4 triggers and each trigger can be selected from available trigger sources.   Author: Kunal Gupta

Read More »

PDB (Programmable Delay Block) Peripheral in automotive microcontroller (NXP S32K144)

What is Programmable Delay Block(PDB) peripheral? PDB provides controllable delays from either an internal or an external trigger, or a programmable interval tick, to the hardware trigger inputs of ADCs. PDB can also provide pulse outputs that are used as the sample window in the CMP block.   The PDB contains a counter whose output is compared to several different digital values. If the PDB is enabled, then a trigger input event will reset the PDB counter and make it start to count. A trigger input event is defined as a rising edge being detected on a selected trigger input source, or if a software trigger is selected and the Software Trigger bit (SC[SWTRIG]) is written with 1 Author: Kunal Gupta

Read More »
CAN Bit TIming
Automotive Protocols
Rohan Singhal

CAN Bit Timing Explained

Bit timing in CAN is all about ensuring that every node on the network can correctly interpret the bits being transmitted. This synchronization is crucial for maintaining the integrity and efficiency of data communication. Bit Segmentation Each bit in a CAN frame is divided into several segments: Synchronization Segment (Sync_Seg): This is the part where the actual synchronization occurs. It’s always one-time quantum (TQ) long and helps align the clocks of all nodes on the network. Propagation Segment (Prop_Seg): This segment compensates for the physical delay in signal propagation across the network. Phase Segment 1 (Phase_Seg1): This is used to compensate for edge phase errors by lengthening the bit time if necessary. Phase Segment 2 (Phase_Seg2): Similar to Phase_Seg1, but it shortens the bit time if necessary. Each of these segments is made up of a certain number of time quanta (TQ), which are the smallest time units in a CAN network. Sample Point The sample point is a critical point within the bit where the bus level is read and interpreted as a logical value. Here’s why it’s so important: Accurate Bit Reading: The sample point is where the CAN controller reads the bit value. It is crucial to set the sample point accurately to minimize errors due to signal noise or other disturbances on the bus. Preferred Value: Typically set at 87.5% of the bit time, this value is preferred by protocols like CANopen and DeviceNet. This means that the bit is sampled after 87.5% of its duration has passed. Adjustable Range: The sample point can vary from 50% to 90% of the bit time, allowing flexibility depending on the network requirements and conditions. For example, ARINC 825 uses a default value of 75%. Noise Minimization: Setting the sample point correctly helps in minimizing the impact of signal noise. Sampling too early or too late can lead to incorrect bit interpretation, especially in noisy environments. Understanding Bit Rate and Bit Timing Bit Rate The bit rate in CAN communication refers to the speed at which data is transmitted over the CAN bus, typically measured in bits per second (bps). The bit rate is a crucial parameter because it determines how quickly data can be sent and received between nodes on the network. Common bit rates in CAN systems include 125 kbps, 250 kbps, and 500 kbps, with some systems operating at even higher speeds, such as 1 Mbps. Bit Timing Bit timing in CAN communication is the precise control of the duration and positioning of each bit transmitted on the bus. Proper bit timing ensures that all nodes on the network sample the bits at the same point, leading to accurate and synchronized data transmission. Bit timing is divided into several segments within each bit time, which collectively ensure robust and reliable communication. How Bit Timing Ensures Synchronization To maintain synchronization, the CAN controller can adjust the length of a bit by an integral number of time quanta (TQ). The maximum value of these adjustments is termed the Synchronization Jump Width (SJW). Hard Synchronization: Occurs on the recessive-to-dominant transition of the start bit. The bit time is restarted from this edge. Resynchronization: Occurs when a bit edge doesn’t occur within the Sync_Seg in a message. One of the Phase Segments is shortened or lengthened, depending on the phase error, up to the SJW. Factors Affecting Bit Rate Four primary factors influence the CAN bit rate: Oscillator Tolerance: Variations in the oscillator frequency can affect the timing accuracy. High-precision oscillators are essential for maintaining a stable bit rate. Propagation Delay: The physical length and quality of the CAN bus can introduce delays. Prop_Seg is adjusted to compensate for these delays. Network Load: Heavy network traffic can lead to delays and timing issues. Proper network design and bit timing configuration help mitigate these problems. Bus Length: Longer bus lengths introduce more propagation delay, requiring adjustments in the Prop_Seg to maintain synchronization. Prescaler Division The prescaler is used to divide the clock frequency to generate the required clock frequency for CAN. For example, if the clock frequency is 48 MHz and we need an 8MHz CAN clock, the prescaler value would be 6. How the Prescaler Division Works Clock Frequency: The original clock frequency provided by the oscillator. Prescaler Value: The value by which the original clock frequency is divided to achieve the desired CAN Clock Frequency. IMPORTANT The CAN system clock is chosen so that the desired CAN bus Nominal Bit Time (NBT) is an integer number of time quanta (CAN system clock periods) from 8 to 25. Time Quanta Definition: The time quantum (tQ) is the basic time unit in CAN bit timing. It is derived from the CAN system clock divided by the prescaler. Calculation: For example, if the CAN system clock is 48 MHz and the prescaler is set to 6, then: Nominal Bit Time (NBT) Definition: The Nominal Bit Time (NBT) is the total duration of a single CAN bit, measured in time quanta (tQ). It is the sum of the time segments within a bit period: Sync_Seg, Prop_Seg, Phase_Seg1, and Phase_Seg2. Components: Sync_Seg: The synchronization segment, always 1 tQ. Prop_Seg: The propagation delay segment, compensates for the signal propagation delay. Phase_Seg1: The first phase segment, can be adjusted to resynchronize the clock. Phase_Seg2: The second phase segment, also adjustable for resynchronization. Calculation: Practical Example of Bit Timing Calculation For calculating Bit Time and Segmentation, some important parameters are taken into account before starting the calculation. Parameters: Bit rate MCU Clock/Oscillator Frequency Bus length Bus propagation delay Propagation delay of TxD plus RxD offered by CAN Transceiver But, usually, values like total propagation delay offered by CAN transceiver, Bus length, and Bus propagation delay, are pre-defined values in their hardware datasheet. Question: Conclusion Understanding CAN bit timing and how the bit rate is adjusted is crucial for ensuring reliable communication in a CAN network. By properly configuring the timing parameters and taking into account factors like oscillator tolerance, propagation delay, network load, and bus length,

Read More »
Kunal Gupta
Author: Kunal Gupta

Author

Kunal Gupta

Leave a comment

Stay Updated With Us

Error: Contact form not found.

      Blog