This document shows the step-by-step process to create a simple 'Blinking_LED' project. There is also a video which demonstrates the same steps. This project uses the S32K144EVB-Q100 EVB, connected to a PC through USB (OpenSDA) connection.
1. New S32DS Project
OR
2. Provide a name for the project, for example 'S32K144_Blinking_LED'. The name must be entered with no space characters.
3. Expand Family S32K1xx, Select S32K144
4. Click Next
5. Click '…' button next to SDKs
6. Check box next to S32K144_SDK.
7. Click OK
8. Click Finish, wait for project generation wizard to complete
9. Notice Processor Expert views have opened.
10. Make sure the project is selected in Project Explorer view, then from the Components - S32K144_Blinking_LED view, select:
Components -> pinmux:PinSettings
11. From the Routing tab, select the GPIO pin routing group and scroll the list until PTD Pin 15 and Pin 16 are visible
12. Click on the fields in the Pin/Signal Selection and Direction columns to set the following:
a. Row: Pin 15, Pin/Signal Selection: PTD15, Direction: Output
b. Row: Pin 16, Pin/Signal Selection: PTD16, Direction: Output
13. Click Save
14. Project -> Generate Processor Expert Code
OR, click the button from the Components view
15. The main.c file from 'Sources' folder should be already open, if not, then in the project window click to expand the project folder then Sources, and finally double click the main.c file to open it.
16. Expand the clock_manager component in the Components Window, then locate CLOCK_DRV_Init
17. Drag and drop the CLOCK_DRV_Init function into main, after the comment 'Write your code here'
18. Now we need to supply an argument so the CLOCK_DRV_Init() function knows what clock settings to use. With clockMan1:clock_manager selected in the Components view, look at the Components Inspector and locate the name of the only clock configuration listed, 'clockMan1_InitConfig0'.
19. Enter the name of the clock configuration, with address operator, to the input arguments of CLOCK_DRV_Init(). Notice the name is shaded grey and a mouse-hover reveals the definition.
21. Expand the pin_mux:PinSettings component in the Components Window
22. Drag and drop the PINS_DRV_Init function into main, below the clock configuration
24. Drag and drop the PINS_DRV_SetPinsDirection function into main immediately after PINS_DRV_Init
25. Drag and drop the PINS_DRV_SetPins function into main
26. Drag and drop the PINS_DRV_ClearPins function into main
27. For each of the PINS_DRV functions, there are 2 arguments, first is always PTD (which is macro defined in SDK), the second is defined as follows:
PINS_DRV_SetPinsDirection: OR-ing of LEDRGB_RED and LEDRGB_GREEN = 1 << 15U | 1 << 16U
PINS_DRV_SetPins: Bit shift of LEDRGB_RED = 1 << 15U
PINS_DRV_ClearPins: Bit shift of LEDRGB_GREEN = 1 << 16U
28. Include an infinite loop after these functions
29. Drag and drop the PINS_DRV_TogglePins function in to main, and place it inside the 'for' loop.
30. Again, the first argument will be PTD and the second is the same as for PINS_DRV_SetPinsDirection above.
31. Within the 'for' loop, and prior to the PINS_DRV_TogglePins function, add a delay of 720000 cycles
int cycles = 720000;
while(cycles--);
32. Build 'Blinking_LED_S32DS'. Select the project name in 'C/C++ Projects' view and then press 'Debug_RAM'. Or you can build for Debug_FLASH, but programming RAM won't overwrite anything you already have in FLASH.
33. After the build completes, check that there are no errors.
34. Open Debug Configurations and select 'Blinking_LED_S32DS_Debug_RAM'
OR
35. Check the Debugger settings and ensure that 'OpenSDA Embedded Debug - USB Port' is selected for interface. Or select the settings which are appropriate for your hardware configuration.
36. Click Debug
37. Set breakpoint on PINS_DRV_TogglePins. Double-click on the blue shaded area at left on the line of code to set breakpoint.
38. Step through initialization calls
39. To see the output register bits change, go to 'EmbSys Registers' tab and expand 'GPIO', then 'PTD' and 'PDOR'. Double-click on PDOR to enable reading of the values.
40. Click resume to advance to the breakpoint, see the LED on board change color.
41. Click resume again and see LED change to other color
My clock_manager component offers six functions starting with "CLOCK_DRV_..." and zero functions starting with "CLOCK_SYS_...". So I am unable to complete the above setup.
CPU is S32K148_144
S32DS 2.2
S32K148_SDK version 3.0.0
Thank you for bringing this to our attention. The SDK had been updated and this document was not. I have now updated it and you should be able to complete by following the new steps.
Best Regards,
Mike
Thanks. The updated images aren't loading in the tutorial above yet, but I think I have what I need.
If I follow the instructions as-is, the call to PINS_DRV_Init() causes the program to get stuck in WDOG_EWM_IRQHandler().
I can use low level calls to initialize the pins without the PINS_DRV_Init(), but I would like to not need to do that.
"New S32DS Application Project" comes with some watchdog disable code. I have tried to use that, but I still get stuck in WDOG_EWM_IRQHandler().
Sorry about that, images fixed now.
Mike
Thanks.
I did notice that File | New | S32DS Project From Example RTM v3.0.0 projects will produce the wrong calls to the old clock functions. So I guess NXP should update those examples too.
One thing I am uncertain about is why S32DS refers to RTM v3.0.0 and not v3.0.2. The RTM folder NXP/s32DS_ARM_v2.2/S32DS/software/S32SDK_S32K1xx_RTM_3.0.0 has release notes for 3.0.0 and 3.0.1 and 3.0.2, but S32DS only refers to 3.0.0. I'm fairly confident I have the latest as this was a recent install.
Hi m.mishrikey@te.com,
The example projects build fine. The functions still exist. The SDK team has implemented more simplified interfaces, and those are what is displayed in the Components view. So we decided to update the tutorial to show the new method, instead of showing where to locate the old interfaces.
I'm not sure why the SDK update 3.0.2 installs and shows still 3.0.0. I've noticed this as well. raresvasile, could you comment on this?
Best Regards,
Mike
27. For each of the PINS_DRV functions, there are 2 arguments, first is always PTD (which is macro defined in SDK), the second is defined as follows:
PINS_DRV_SetPinsDirection: OR-ing of LEDRGB_RED and LEDRGB_GREEN = 1 << 15U | 1 << 16U
PINS_DRV_SetPins: Bit shift of LEDRGB_RED = 1 << 15U
PINS_DRV_ClearPins: Bit shift of LEDRGB_GREEN = 1 << 16U
I'm going to need some explanation of what's happening in step 27.
In pins_drivers.h is says the first argument is not always PTD. Is pins_drivers.h what you're referring to as "macro defined in SDK"?
* @param[in] base GPIO base pointer (PTA, PTB, PTC, etc.)
* @param[in] pin The pin number for which to configure the direction
* @param[in] direction The pin direction:
* - 0: corresponding pin is set to input
* - 1: corresponding pin is set to output
*/
void PINS_DRV_SetPinDirection(GPIO_Type * const base,
pins_channel_type_t pin,
pins_level_type_t direction);
I can see that you are ORing the bit shifted 15 and 16 so that you can do both pins with a single command but this style of C is not familiar to me and was very confusing at first glance. Maybe it's because I'm not used to working with 32bit registers or because I generally use macros to define these things to be more human readable.
Here is my real question though:
Why is any of this necessary when using the processor expert? It looks like all of my pins are already setup in pin_mux.c, for instance:
{
.base = PORTE,
.pinPortIdx = 8u,
.pullConfig = PORT_INTERNAL_PULL_NOT_ENABLED,
.passiveFilter = false,
.driveSelect = PORT_LOW_DRIVE_STRENGTH,
.mux = PORT_MUX_AS_GPIO,
.pinLock = false,
.intConfig = PORT_DMA_INT_DISABLED,
.clearIntFlag = false,
.gpioBase = PTE,
.direction = GPIO_OUTPUT_DIRECTION,
.digitalFilter = false,
.initValue = 0u,
},
It seems redundant to do steps 10-12 then manually write code that does it again. Am I fundamentally misunderstanding what the processor expert is doing?
This is my first time working with Design Studio so I apologize for any misunderstanding.
In the example, there are two LEDs. One is on PORTD pin 15, and the other on PORTD pin 16.
They didn't have to be there - they could have been on a different GPIO port. Or one could have been on PORTC whilst the other on PORTA. That's just they way they set up this example.
They way you set a pin, or clear a pin, or toggle a pin with the SDK functions is using simple bit passing.
If you wanted to turn on PTD0, you would do
PINS_DRV_SetPins(PTD, 1);
If you wanted to turn on PTD2, you would do
PINS_DRV_SetPins(PTD, 0b100);
If you wanted to turn on PTD5 and PTD1, you would do
PINS_DRV_SetPins(PTD, 0b100010);
If you wanted to turn on PTDn, you would do
PINS_DRV_SetPins(PTD, 1<<n);
If you wanted to turn on PTDx and PTDy and PTDz, you would do
PINS_DRV_SetPins(PTD, ((1<<x) | (1<<y) | (1<<z)));
PEX will do the initial pin config for you . So if you wanted a pin to initialize high after pin configuration, then you would set that pin in PEX and it would show .initValue = 1u.
But what if you wanted to change that pin during runtime? Like if a user pushes a button, and you want that button push to toggle or disable the LED? Simply call the desired function when needed.
If the pin direction was correct in the PEX setup, then setting the pin direction again may indeed be redundant. What if you had a board where when a switch is in one position, an LED shows a state, and when it is in another position, a signal is read back? You might need to change pin directions dynamically, and you have the flexibility to do so. The SDK functions make it very easy to do so.
It seems you answered questions that I didn't ask. I will post the answers I've found so that there is closure to the topic for future readers.
No, pins_drivers.h is not what is being referred to as "macro defined in SDK". PTD is defined as a macro in S32K144.h to represent the value 0x400FF0C0.
/** Peripheral PTD base address */
#define PTD_BASE (0x400FF0C0u)
/** Peripheral PTD base pointer */
#define PTD ((GPIO_Type *)PTD_BASE)
It should also be noted that, as referenced in pins_drivers.h, the first argument is not always PTD, but whatever GPIO register you would like to interact with. Though I didn't ask that question directly (simply made a statement referencing the header file) because I was pretty sure of the answer, I'm now confident in the statement so I want to eliminate any ambiguity.
When I discussed the format not looking familiar it's because I always #define pins with human readable names so that the code is easier to navigate. For instance, instead of using:
PINS_DRV_SetPins(PTD, 1 << 15U);
I would have used:
PINS_DRV_SetPins(PTD, LED1_PIN);
Because the Processor Expert pops out this macro in pin_mux.h:
/*! @brief User Pin definitions for PTD15 */
#define LED1 PTD
#define LED1_PIN 15U
Technically, I would have had PINS_DRV_SetPins take a single argument and I would have had shortened the command to just SetPin().
No, none of that was necessary when using the processor expert. If you use processor expert to set up your pins (step 12) then you do not have to setup your pins again in the main function. The following 3 lines make no changes to the program:
PINS_DRV_SetPinsDirection: OR-ing of LEDRGB_RED and LEDRGB_GREEN = 1 << 15U | 1 << 16U
PINS_DRV_SetPins: Bit shift of LEDRGB_RED = 1 << 15U
PINS_DRV_ClearPins: Bit shift of LEDRGB_GREEN = 1 << 16U