开发板测评系列五 | NXP S32K312 VSCode 开发环境搭建

随着 AI 工具的普及,特别是 cline 和 curie,让大家看到了"未来的开发方式“

越来越多的开发者开始使用 VSCode 作为主力编辑器。本文将介绍如何安装 VSCode 并配置相关插件,以便于开发者更高效地进行嵌入式开发。

1.   安装 VSCode

下载并安装 VSCode,下载地址:https://code.visualstudio.com/

2.   安装插件

VSCode  是一个开源编辑器,功能强大,但是功能并不全面,需要安装插件来扩展功能。

2.1   安装 C/C++ 插件

C/C++ 插件是 VSCode 官方提供的插件,可以高亮显示 C/C++ 代码,

提供语法检查、代码格式化、代码跳转等功能。这些不必多说网上的资料太多了

2.2   安装嵌入式插件

嵌入式插件是专门为嵌入式开发者设计的插件,提供了各种工具,也是我介绍的重点如:

1、EIDE 开发环境插件

一个国内开发者开发的插件,给我们的嵌入式开发带来了全新的开发体验
大家有问题也可以去官方论坛提问,或者在 GitHub 上提 issue。

2、Cortex-Debug 调试插件

开源的调试工具,支持 JTAG、SWD、Serial 等多种调试方式,可以方便地进行调试。

3.   配置 VSCode

VSCode  的配置非常简单,只需要按需安装插件,并设置相关参数即可。

EIDE 插件配置

编译

EIDE 本质上是将其他开发环境的配置移值到 VSCode,使得 VSCode 可以直接导入其他开发环境的工程。例如 KEIL,eclipse 的工程,还是需要下载 KEIL 或者 DS IDE 来为我们提供官方编译器。

上次的文章介绍了 DS IDE 的安装、使用方法,这里就不再赘述了。DS IDE 是根据 eclipse 的进行二次开发的。导入 EIDE 中就需要选择“导入项目”的 Eclipse 选项:

然后选择我们要导入的 Eclipse 工程的.cproject:例如

之后我们就有了一个工程区了

但是毕竟我们是根据插件进行开发,我们需要再进行一些配置才能正常编译:
首先是编译器路径,我们需要配置编译器的路径,这里我选择的是 DS IDE 的编译器:右键点击“构建配置”

可以参考我的编译器路径自己找一下

然后我们需要配置编译器包含项目路径,大部分不用我们配置,可以通过直接编译项目来看看哪些头文件我们没包含进来:

例如 RTD 的库文件路径,大家可以参考我的来找一下自己的路径:

最后我们的编译器还需要连接一个 LD 文件,可能需要你做修改

编译器选项的连接器

选择自己需要的 ld 文件路径

如果添加了新的文件夹或者其他资源需要添加到项目资源中

这个就是我自己添加的代码

之后就可以正常编译了,编译完成之后我们就可以看到编译的结果:

和 S32DS 一样设置更加方便

烧录

我的烧录是使用 JLink,所以我们需要配置一下 JLink 的路径:

烧录比较麻烦完全是使用 JFlash 进行烧录所以每次编译完,我一般使用 debug 模式进行调试来烧录所以 Cortex-Debug 调试插件就非常好用了,我们只需要配置一下烧录的设置就可以了:

在.VSCode 文件夹中创建 launch.json 文件,内容如下大家可以参考

 {

// Use IntelliSense to learn about possible attributes.

 

// Hover to view descriptions of existing attributes.

 

// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0",

"configurations": [

{

"type": "cortex-debug",

 

"request": "launch",

 

"name": "Debug J-Link",

 

"cwd": "${workspaceRoot}",

 

"executable": "F:\\S32_workspace\\LED_test\\build\\Debug_FLASH\\LED_test.elf", "serverpath": "D:\\JLink_V812\\JLinkGDBServerCL.exe",

"servertype": "jlink",

 

"device": "S32K312",

 

"interface": "jtag",

 

"serialNumber": "" //If you have more than one J-Link probe, add the serial number here.

}

]

}

按下调试按键,代码会自动烧录并且进入调试模式

试用

有了基本的嵌入式开发工具,我们就可以感受到 VSCode 的强大之处了,比较 KEIL 和 eclipse 要现代化的多

有了按键的引脚定义我们可以先在 DS IDE 中自动生成代码。之后完全可以用 VSCode 进行开发了。

强大的跳转以及插件的支持我们可以很快找到库函数中我们需要的函数,然后进行修改。

/**

Function Name : Siul2_Dio_Ip_ReadPins

Description : This function returns the current input values from a Only pins

configured as input will have meaningful



@implements Siul2_Dio_Ip_ReadPins_Activity

*/

Siul2_Dio_Ip_PinsChannelType Siul2_Dio_Ip_ReadPins(const Siul2_Dio_Ip_GpioType * const base)

{

SIUL2_DIO_IP_DEV_ASSERT(NULL_PTR != base);

Siul2_Dio_Ip_PinsChannelType returnValue = 0U; returnValue = Siul2_Dio_Ip_ReadPinsRunTime(base); return returnValue;

}

 

读取电平的函数找到,调试一下看看具体怎么使用

vale = Siul2_Dio_Ip_ReadPins(SW3_PORT); vale = Siul2_Dio_Ip_ReadPins(SW4_PORT);

添加到监视里,和 keil 的调试方法比较类似。可以看到变量的值,可以设置断点,可以单步调试,可以查看堆栈等等。

按下 SW3 按键,调试时可以查看按下后值的变化

按下 SW4 按键,调试时可以查看按下后值的变化

有了调试的值我们就可以完成按键的全部功能开发了,

按键的电平很好判断,分别是 vale 的 bit8 和 bit9,所以我们可以根据按键的电平来完成我们的按键结构体的构建。

按键一般需要识别单击、双击、长按等逻辑,我移植了自己比较喜欢的库”multi_button“,可以实现多种按键功能

multi_button.h




/*

Copyright (c) 2016 Zibin Zheng <znbin@qq.com>

All rights reserved

*/

 

#ifndef _MULTI_BUTTON_H_ #define _MULTI_BUTTON_H_

 

#include "inc.h"

 

#include "Siul2_Port_Ip.h" #include "Siul2_Dio_Ip.h"

 

#include <stdint.h> #include <string.h>

 

// According to your need to modify the constants. #define TICKS_INTERVAL 10// ms

#define DEBOUNCE_TICKS 3 // MAX 7 (0 ~ 7) #define SHORT_TICKS (300 / TICKS_INTERVAL) #define LONG_TICKS (1000 / TICKS_INTERVAL)

 

// button handle list head.

static struct Button *head_handle = NULL; static struct Button btn_SW3;

static struct Button btn_SW4; typedef void (*BtnCallback)(void *);

typedef enum {

PRESS_DOWN = 0, // 按钮按下事件 PRESS_UP, // 按钮释放事件 PRESS_REPEAT, // 按钮重复按下事件 SINGLE_CLICK, // 单击事件 DOUBLE_CLICK, // 双击事件 LONG_PRESS_START,// 长按开始事件 LONG_PRESS_HOLD, // 长按保持事件 number_of_event, // 事件数量 NONE_PRESS // 无按下状态

} PressEvent;

 

typedef struct Button Button;// 先声明Button结构体

typedef struct Button {

uint16_t                      ticks;                              // 记录按键触发的时钟周期数

uint8_t                       repeat                              :4;// 记录按键重复触发的次数

uint8_t                       event                              :4;// 按键事件类型

uint8_t                       state                              :3;// 按键当前状态

uint8_t                          debounce_cnt:3;// 消抖计数器

uint8_t                          active_level:1;// 按键有效电平

uint8_t                           button_level:1;// 当前按键物理电平

const Siul2_Dio_Ip_GpioType *base;                                          // 按键引脚基地址




uint8_t                       id;                              // 按键ID号

uint8_t (*hal_button_Level)(Button *);                                         // 获取按键物理电平

// uint8_t (*hal_button_Level)(uint8_t button_id_); BtnCallback                cb[number_of_event];// 按键事件回调函数数组 struct Button *next;                // 指向下一个按键结构体的指针

} Button;

 

#ifdef  cplusplus extern "C" { #endif

 

void        button_init(struct Button *handle, uint8_t active_level,

const Siul2_Dio_Ip_GpioType *button_id, uint8_t id);

void   button_attach(struct Button *handle, PressEvent event, BtnCallback cb); PressEvent get_button_event(struct Button *handle);

int button_start(struct Button *handle); void button_stop(struct Button *handle); void button_ticks(void);

 

#ifdef   cplusplus

}

#endif #endif

 

multi_button.C




/*

Copyright (c) 2016 Zibin Zheng <znbin@qq.com>

All rights reserved

*/

 

#include "multi_button.h"

 

#define EVENT_CB(ev) \ if (handle->cb[ev]) \

handle->cb[ev]((void *) handle)

// 定义了一个宏  EVENT_CB,用于检查并调用指定事件的回调函数,

// 如果该回调函数已设置,则传递 handle 作为参数。 #define PRESS_REPEAT_MAX_NUM 15// 按键重复次数最大值 static void button_handler(struct Button *handle);

uint8_t Button_read(Button *this)

{

Siul2_Dio_Ip_PinsChannelType val = Siul2_Dio_Ip_ReadPins(this->base);

 

val = (val >> 8) & (this->id); if (val == this->id)

return 1;

return 0;

}

 

/**

@brief Initializes the button struct

@param handle: the button handle

@param pin_level: read the HAL GPIO of the connected button

@param active_level: pressed GPIO

@param button_id: the button

@retval None

*/

void button_init(struct Button *handle, uint8_t active_level,

const Siul2_Dio_Ip_GpioType *button_id, uint8_t id)

{

memset(handle, 0, sizeof(struct Button)); handle->event = (uint8_t) NONE_PRESS; handle->button_level = !active_level;

handle->active_level = active_level; handle->base = button_id;

handle->id            = id;

 

handle->hal_button_Level = Button_read;

}

 

/**

@brief Attach the button event callback

@param handle: the button handle




@param event: trigger event

@param cb: callback

@retval None

*/

void button_attach(struct Button *handle, PressEvent event, BtnCallback cb)

{

handle->cb[event] = cb;

}

 

/**

@brief Inquire the button event

@param handle: the button handle

@retval button

*/

PressEvent get_button_event(struct Button *handle) { return (PressEvent) (handle->event); }

 

/**

@brief Button driver core function, driver state

@param handle: the button handle

@retval None

*/

static void button_handler(struct Button *handle)

{

uint8_t read_gpio_level = handle->hal_button_Level(handle);

 

// ticks counter working.. if ((handle->state) > 0)

handle->ticks++;

 

/*             button debounce handle               */

if (read_gpio_level != handle->button_level) {// not equal to prev one

// continue read 3 times same new level change

if (++(handle->debounce_cnt) >= DEBOUNCE_TICKS) { handle->button_level = read_gpio_level; handle->debounce_cnt = 0;

}

} else {// level not change ,counter reset. handle->debounce_cnt = 0;

}

 

/* State machine */ switch (handle->state) {

case 0:

if (handle->button_level == handle->active_level) {// start press down handle->event = (uint8_t) PRESS_DOWN;

EVENT_CB(PRESS_DOWN);

handle->ticks = 0;

handle->repeat = 1;

handle->state = 1;

} else {

handle->event = (uint8_t) NONE_PRESS;




}

break;

 

case 1:

if (handle->button_level != handle->active_level) {// released press up handle->event = (uint8_t) PRESS_UP;

EVENT_CB(PRESS_UP);

handle->ticks = 0;

handle->state = 2;

} else if (handle->ticks > LONG_TICKS) { handle->event = (uint8_t) LONG_PRESS_START; EVENT_CB(LONG_PRESS_START);

handle->state = 5;

}

break;

 

case 2:

if (handle->button_level == handle->active_level) {// press down again handle->event = (uint8_t) PRESS_DOWN;

EVENT_CB(PRESS_DOWN);

if (handle->repeat != PRESS_REPEAT_MAX_NUM) { handle->repeat++;

}

EVENT_CB(PRESS_REPEAT);// repeat hit handle->ticks = 0;

handle->state = 3;

} else if (handle->ticks > SHORT_TICKS) {// released timeout if (handle->repeat == 1) {

handle->event = (uint8_t) SINGLE_CLICK;

EVENT_CB(SINGLE_CLICK);

} else if (handle->repeat == 2) {

handle->event = (uint8_t) DOUBLE_CLICK; EVENT_CB(DOUBLE_CLICK);// repeat hit

}

handle->state = 0;

}

break;

 

case 3:

if (handle->button_level != handle->active_level) {// released press up handle->event = (uint8_t) PRESS_UP;

EVENT_CB(PRESS_UP);

if (handle->ticks < SHORT_TICKS) { handle->ticks = 0;

handle->state = 2;// repeat press

} else {

handle->state = 0;

}

} else if (handle->ticks

> SHORT_TICKS) {// SHORT_TICKS < press down hold time < LONG_TICKS handle->state = 1;




}

break;

 

case 5:

if (handle->button_level == handle->active_level) {

// continue hold trigger

handle->event = (uint8_t) LONG_PRESS_HOLD; EVENT_CB(LONG_PRESS_HOLD);

} else {// released

handle->event = (uint8_t) PRESS_UP; EVENT_CB(PRESS_UP);

handle->state = 0;// reset

}

break; default:

handle->state = 0;// reset break;

}

}

 

/**

@brief Start the button work, add the handle into work

@param handle: target handle

@retval 0: -1: already exist.

*/

int button_start(struct Button *handle)

{

struct Button *target = head_handle; while (target) {

if (target == handle)

return -1;// already exist. target = target->next;

}

handle->next = head_handle; head_handle = handle; return 0;

}

 

/**

@brief Stop the button work, remove the handle off work

@param handle: target handle

@retval None

*/

void button_stop(struct Button *handle)

{

struct Button **curr;

for (curr = &head_handle; *curr;) { struct Button *entry = *curr; if (entry == handle) {

*curr = entry->next;

//                   free(entry);




return;// glacier add 2021-8-18

} else {

curr = &entry->next;

}

}

}

 

/**

@brief background ticks, timer repeat invoking interval

@param

@retval None

*/

void button_ticks(void)

{

struct Button *target;

for (target = head_handle; target; target = target->next) { button_handler(target);

}

}

 

 

 

main.C

 

 

int main(void)

{

Siul2_Port_Ip_Init(NUM_OF_CONFIGURED_PINS_PortContainer_0_BOARD_InitPeripherals, g_pin_mux_InitConfigArr_PortContainer_0_BOARD_InitPeripherals);

button_init(&btn_SW3, 1, SW3_PORT, 1);

button_init(&btn_SW4, 1, SW4_PORT, 2); button_start(&btn_SW3);

button_attach(&btn_SW3, PRESS_DOWN, app1);// 单击

button_start(&btn_SW4);

button_attach(&btn_SW4, DOUBLE_CLICK, app2);// 双击

 

// Potentiometer_Init(); while (1) {

Delay_ms(5);// 延时

// LED_run(Inc_task_init.LED_running); button_ticks();

if (val == 1) {

Siul2_Dio_Ip_TogglePins(red_LED_PORT, (1 << red_LED_PIN)); val = 0;

} else if (val == 2) {

Siul2_Dio_Ip_TogglePins(red_LED_PORT, (1 << red_LED_PIN)); val = 0;

}

}

 

return exit_code;

}

编译的时候需要添加头文件路径,在 EIDE 设置中添加我们的头文件路径

快捷键 F7 编译

这样单击、双击的功能就实现了,可以根据自己的需求进行修改。接下来就可以让按键的功能绑定我们的其他功能了,先写一个 ADC 的读取

在 DS IDE 中外设设置里添加 ADC 模块和 platform ADC 不用多说,platform 是为了启用中断

看一下 ADC 的配置

1.adcconfigset

中断

通道

读取

2.AdcGeneral



Potentiometer.h

#ifndef POTENTIOMETER_H_ #define POTENTIOMETER_H_

 

#include "Inc.h" #include "IntCtrl_Ip.h" #include "Adc_Sar_Ip.h" #include "Adc.h" #include "Platform.h"

 

#define NUM_RESULTS (1u) // buffer大小 #define RESULT_BUFF_VAL (0xaaaa)// 初始化 #define ADC_RESULT_BUFF_VAL (0xbbbb)// 初始化

 

extern ISR(Adc_Sar_0_Isr);

 

void Potentiometer_Init(void); void ADC_get();

 

#endif /* POTENTIOMETER_H_ */

 

 

Potentiometer.c




#include "Potentiometer.h"

 

Adc_ValueGroupType ResultBuffer[NUM_RESULTS] = {RESULT_BUFF_VAL};

 

volatile uint8 VarNotification_0 = 0u; Std_ReturnType StdReturn = E_NOT_OK; volatile boolean bStatus = TRUE;

 

void ADC0_Notification(void) { VarNotification_0++; }// 中断函数

 

void Potentiometer_Init(void)

{

#if (ADC_CALIBRATION == STD_ON)

Adc_CalibrationStatusType CalibStatus; #endif

//注册中断函数

Platform_InstallIrqHandler(ADC0_IRQn, Adc_Sar_0_Isr, NULL_PTR); Platform_SetIrq(ADC0_IRQn, TRUE);

#if (ADC_PRECOMPILE_SUPPORT == STD_ON)

Adc_Init(NULL_PTR); #else

Adc_Init(&Adc_Config);

#endif /* (ADC_PRECOMPILE_SUPPORT == STD_ON) */

 

#if (ADC_CALIBRATION == STD_ON)

/* Calibrate the first hardware unit used for Interrupt. */

/* Call Calibration function multiple times, to mitigate instability of board source */ for (uint8 Index = 0; Index <= 5; Index++) {

Adc_Calibrate(AdcHwUnit_0, &CalibStatus);

if (CalibStatus.AdcUnitSelfTestStatus == E_OK) { break;

}

}

/* Fail if calibration did not succeed after multiple attempts. */ if (Index > 5) {

bStatus = FALSE;

}

#endif /* (ADC_CALIBRATION == STD_ON) */

 

if (bStatus) {

/* Part 1: Example with SW Triggered One-Shot Conversion Mode, data conversion is updated by

* Interrupt.*/

/************************************************************************************************

/* ResultBuffer is updated new data in Adc_Sar_0_Isr handler */ Adc_SetupResultBuffer(AdcGroup_0, ResultBuffer); Adc_EnableGroupNotification(AdcGroup_0);

 

for (uint8 Index = 0u; Index < 10u; Index++) { VarNotification_0 = 0; Adc_StartGroupConversion(AdcGroup_0);




/* Check if notification is called */ while (VarNotification_0 == 0u) {

}

 

StdReturn = Adc_ReadGroup(AdcGroup_0, ResultBuffer); if (E_OK != StdReturn) {

bStatus = FALSE; break;

}

}

}

}

 

void ADC_get(void)

{

Adc_SetupResultBuffer(AdcGroup_0, ResultBuffer); Adc_EnableGroupNotification(AdcGroup_0); Adc_StartGroupConversion(AdcGroup_0); Adc_ReadGroup(AdcGroup_0, ResultBuffer);

}

绑定双击按键和读取 ADC 采样值

双击读取到 adc 采样的范围 0X00(右)~0X3FF9(左)

利用 DS IDE 生成底层代码后,功能编写和调试代码的过程全部是使用 vscode 来进行的,非常方便,而且有很多插件可以提高效率,比如 C/C++的语法高亮、代码格式化、代码补全、编译、调试等等。

更不要说 AI 的智能提示,代码模版和提问、git 的版本管理、编译器的错误提示等等,这些都可以让你在开发过程中少走很多弯路。

文章来自“S32K312 开发板评测活动”测评者:劉瑞陽

欢迎在博文下方留言评论,我们会及时回复您的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值