不爱胡萝卜的仓鼠

  • 2024-07-03
  • 加入了学习《DigiKey 应用说:蓝牙5.4 新特性解读及实例演示》,观看 蓝牙5.4 新特性解读及实例演示

  • 2024-06-18
  • 回复了主题帖: [STM32MP135F-DK]测评 ②烧录一个新系统

    zhgongzuoshi 发表于 2024-6-17 15:35 淘宝绿联店买的,貌似是带的? 我感觉他说的5V3A是在QC3.0握手成功后才会激活,开发板肯定是没有快充协议的握手的,在没有握手的情况下这个插头可能就只给默认的功率(我猜的),你可以换个那种没有协议的但是功率给的够勾的开关电源或者大板砖电源。如果你手上有万用表和水泥电阻,可以试试看,你这个电源在默认情况下能不能给出5V3A的输出

  • 2024-06-17
  • 回复了主题帖: [STM32MP135F-DK]测评 ②烧录一个新系统

    zhgongzuoshi 发表于 2024-6-16 21:13 博主,您用的什么电源呢,我特意在绿联买了5V3A的适配器和线, 依然是这个样子呢: Previous ADC mea ... 你这个5V3A的插头或者线是不是有协议?

  • 2024-04-10
  • 回复了主题帖: [STM32MP135F-DK]测评 ④安装SDK及HelloWorld

    2609 发表于 2024-3-24 00:36 老哥我也是卡在最后乱码的问题,你文章中提到的source具体是怎样操作的,我在虚拟机里make的结果是这样 ... 就是这句 source SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi  

  • 2024-01-14
  • 发表了主题帖: [STM32MP135F-DK]测评 ⑨GPIO输入

            按照之前的测评计划,还差一篇人机交互相关功能测评(按键、显示屏、触摸等),因为触摸和显示屏的功能是原厂直接做好了的,并且在之前的GTK相关文章中也使用了显示屏和触摸,那么我就写一下按键吧,其本质也就是GPIO输入。         之前写过一篇关于 GPIO输出的,就是点灯,今天来做一下GPIO INPUT的试验。         因为之前点灯时已经发现开发板上的用户按键已经被占用,那我就使用一下CN8这一大堆的GPIO   通过文档可以查询到全部引脚的说明,如下图所示 使用在点灯中用过的gpioinfo指令,和表格对应,看那个GPIO没有被使用。我这边随便找了一个PB1,对应就是gpiochip1的line 1   接下来就是基于之前的点灯代码,改成GPIO input的代码,代码如下 #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <linux/gpio.h> int main(int argc, char **argv) { struct gpiohandle_request req; struct gpiohandle_data data; char chrdev_name[20]; int fd, ret; strcpy(chrdev_name, "/dev/gpiochip1"); /* 打开GPIO设备 */ fd = open(chrdev_name, 0); if (fd == -1) { ret = -errno; fprintf(stderr, "Failed to open %s\n", chrdev_name); return ret; } /* 设置使用的几号GPIO,和输入输出模式等 */ req.lineoffsets[0] = 1;//1号,与之前的gpiochip1组合,即表示PB1 req.flags = GPIOHANDLE_REQUEST_INPUT;//输入模式 req.lines = 1; // 只请求一个线路的句柄 req.consumer_label[0] = '\0'; // 不需要为读取设置任何标签或默认值 /* 获取GPIO的输入句柄 */ ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); /* 如果获取失败 */ if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n", ret); } /* 已经获取到/获取失败句柄,关闭文件描述符 */ if (close(fd) == -1) { perror("Failed to close GPIO character device file"); } /* 定时1s查询GPIO状态并打印 */ while(1) { /* 获取GPIO状态 */ ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); /* 如果获取失败 */ if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue %s (%d)\n", "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret); } else { /* 打印获取到的GPIO电平 */ printf("value: %d\n", data.values[0]); // 打印读取到的GPIO值(0或1) } /* delay 1S */ sleep(1); } /* 释放GPIO句柄文件描述符 */ ret = close(req.fd); if (ret == -1) { perror("Failed to close GPIO LINEHANDLE device file"); ret = -errno; } return ret; } 配套的makefile文件如下 PROG = gpioInput SRCS = gpioInput.c OBJS = $(SRCS:.c=.o) CLEANFILES = $(PROG) # Add / change option in CFLAGS if needed # CFLAGS += <new option> $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) .c.o: $(CC) $(CFLAGS) -c $< -o $@ all: $(PROG) clean: rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ 这个代码实现的功能就是,初始化PB1为输入模式,然后每隔1S打印GPIO的电平状态 如何编译代码和运行,我就不赘述了,和之前的操作一致 使用杜邦线给GPIO一个低电平(连接GND)或一个高电平(连接3.3V),即可在打印中看到GPIO读取的电平状态,代码运行效果如下 [localvideo]fadb56a025ddf5051c8af29969772eac[/localvideo]  

  • 2023-12-25
  • 回复了主题帖: [STM32MP135F-DK]测评 ⑦MP135 GTK与中文

    dukedz 发表于 2023-12-25 14:05 把字体文件(.ttf .ttc 等后缀)拷贝到 当前用户 home 目录下的 .fonts 目录下,即可完成字体安装 👌,非常感谢,晚上回去我试一下

  • 回复了主题帖: [STM32MP135F-DK]测评 ⑦MP135 GTK与中文

    qiao--- 发表于 2023-12-25 14:03 可以,今天晚上之前我出一期移植这个字库的测评,你关注一下 好嘞,非常感谢

  • 回复了主题帖: [STM32MP135F-DK]测评 ⑦MP135 GTK与中文

    qiao--- 发表于 2023-12-25 11:40 把win系统的字库移植到板子上去,我编写QT程序的时候也不能显示中文,后来我直接把win 的字库移植到板 ... 能请教一下具体怎么操作吗?

  • 回复了主题帖: [STM32MP135F-DK]测评 ⑦MP135 GTK与中文

    lugl4313820 发表于 2023-12-25 13:23 这个可以跑touchGFX吗?实时性高不高呀? 这个是跑了linux系统的,不能跑TouchGFX。当然135也支持裸机开发,和普通的STM32单片机一样,但是依然不支持TouchGFX(之前听ST工程师说后续可能会支持,但什么时候未知),目前裸机下已支持的是LVGL。还有就是裸机不支持Keil,要么IAR要么ST自己的IDE,因为Keil不支持A核

  • 2023-12-24
  • 发表了主题帖: [STM32MP135F-DK]测评 ⑧使用GTK制作一个时钟+天气预报demo

    本帖最后由 不爱胡萝卜的仓鼠 于 2023-12-26 13:32 编辑         之前跑helloWorld的时候绘制UI使用的就是GTK,那么我这次也使用GTK,本来想在帖子中记录一下我一步一步探索的情况,但是实际情况太复杂,这个GTK我是第一次上手,兜兜转转搞了搞几天,全写下来的话内容是在太多了,我这边只能简单讲一下demo的基本情况,最终我会把demo的源码贴出来,具体的请大家自行阅读代码。                 在之前的几个帖子中,我已经掌握了基础的编译文件、下载运行代码、自动更新时间、获取天气信息等,基本上已经满足了制作demo的条件,现在就差学习一下如何使用GTK绘制界面了。(当然还有使用curl库从HTTPS下载天气的json数据、解析天气json数据。但是这两个我觉得还是很快可以上手的)         首先要去找一下GTK的官方文档,官网网址我放一下:https://www.gtk.org,我需要其中的API文档,连接如下:https://docs.gtk.org/gtk3/,这里面有快速上手的说明文档还有API说明。         说一下目标:全屏显示,显示当前年月日时分秒、显示天气预报(因为之前申请的是免费无限制接口,只能获取当前天气,反正大致意思到了就行)、一个刷新按钮,(用于手动刷新天气信息,当然代码也会定时自动刷新)、一个退出按钮(用于退出整个程序,因为全屏了,没有右上角的X了)         整个C代码如下 #include <gtk/gtk.h> #include <glib.h> #include <stdio.h> #include <time.h> #include <curl/curl.h> #include <json-c/json.h> #define FULLSCREEN (1) /* 界面布局是否从UI文件加载 */ #define LOAD_UI_FROM_FILE (1) #if !LOAD_UI_FROM_FILE #define BOX (1) #define GRID (2) #define BOX_OR_GRID (BOX) #endif char weather_URL[] = "请求天气预报的https连接"; char outfilename[] = "weatherData.json"; void get_weather_data_and_refresh(GtkWidget *widget); /* 更新时间的回调函数 */ gboolean update_time(GtkWidget *widget) { time_t current_time; struct tm *time_info; char time_string[30]; current_time = time(NULL); time_info = localtime(&current_time); strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", time_info); gtk_label_set_text(GTK_LABEL(widget), time_string); /* 返回true,继续执行定时器 */ return TRUE; } /* 首次运行更新天气 */ gboolean first_run_update_weather(GtkWidget *widget) { get_weather_data_and_refresh(widget); /* 返回FALSE,不再继续执行定时器 */ return FALSE; } /* 更新天气 */ gboolean update_weather(GtkWidget *widget) { get_weather_data_and_refresh(widget); /* 返回true,继续执行定时器 */ return TRUE; } /* 天气代码转英文字符 */ void weather_code_to_english_text(int code, char *text) { switch(code) { case 0: { strcpy(text, "Sunny"); } break; case 1: { strcpy(text, "Clear"); } break; case 2: { strcpy(text, "Fair"); } break; case 3: { strcpy(text, "Fair"); } break; case 4: { strcpy(text, "Cloudy"); } break; case 5: { strcpy(text, "Partly Cloudy"); } break; case 6: { strcpy(text, "Partly Cloudy"); } break; case 7: { strcpy(text, "Mostly Cloudy"); } break; case 8: { strcpy(text, "Mostly Cloudy"); } break; case 9: { strcpy(text, "Overcast"); } break; case 10: { strcpy(text, "Shower"); } break; case 11: { strcpy(text, "Thundershower"); } break; case 12: { strcpy(text, "Thundershower with Hail"); } break; case 13: { strcpy(text, "Light Rain"); } break; case 14: { strcpy(text, "Moderate Rain "); } break; case 15: { strcpy(text, "Heavy Rain"); } break; case 16: { strcpy(text, "Storm"); } break; case 17: { strcpy(text, "Heavy Storm"); } break; case 18: { strcpy(text, "Severe Storm"); } break; case 19: { strcpy(text, "Ice Rain"); } break; case 20: { strcpy(text, "Sleet"); } break; case 21: { strcpy(text, "Snow Flurry "); } break; case 22: { strcpy(text, "Light Snow"); } break; case 23: { strcpy(text, "Moderate Snow"); } break; case 24: { strcpy(text, "Heavy Snow"); } break; case 25: { strcpy(text, "Snowstorm"); } break; case 26: { strcpy(text, "Dust"); } break; case 27: { strcpy(text, "Sand"); } break; case 28: { strcpy(text, "Duststorm"); } break; case 29: { strcpy(text, "Sandstorm"); } break; case 30: { strcpy(text, "Foggy"); } break; case 31: { strcpy(text, "Haze"); } break; case 32: { strcpy(text, "Windy"); } break; case 33: { strcpy(text, "Blustery"); } break; case 34: { strcpy(text, "Hurricane"); } break; case 35: { strcpy(text, "Tropical Storm"); } break; case 36: { strcpy(text, "Tornado"); } break; case 37: { strcpy(text, "Cold"); } break; case 38: { strcpy(text, "Hot"); } break; default: { strcpy(text, "Unknown"); } break; } } /* 解析天气json数据,如果成功填充字符串 */ int parse_weather_json_data(char *weather_data) { char weather_text[30]; /* 从文件中解析JSON数据 */ json_object *parsed_json = json_object_from_file(outfilename); /* 如果JSON解析失败 */ if (parsed_json == NULL) { printf("failed to parse weather json data\n"); sprintf(weather_data, "failed to parse weather data"); } /* 解析成功 */ else { printf("success to parse JSON data\n"); // printf("weather json data: %s\n", json_object_to_json_string(parsed_json)); /* 找第一层results */ json_object *results = json_object_object_get(parsed_json, "results"); // printf("results: %s\n", json_object_get_string(results)); if (results != NULL) { for (int i = 0; i < json_object_array_length(results); i++) { /* results的数组的第i个 */ json_object *results_obj = json_object_array_get_idx(results, i); /* 找到第二层的now */ json_object *now = json_object_object_get(results_obj, "now"); if (now != NULL) { /* 得到天气的code和温度数据 */ int code = json_object_get_int(json_object_object_get(now, "code")); const char *temperature = json_object_get_string(json_object_object_get(now, "temperature")); // printf("code: %d\n", code); // printf("temperature: %s\n", temperature); /* 天气code转成英文字符 */ weather_code_to_english_text(code, weather_text); /* 组装整个天气的字符串 */ sprintf(weather_data, "now weather: %s now temperature: %s\n", weather_text, temperature); } else { printf("can't find now\n"); } } } else { printf("can't find results\n"); } /* 释放JSON对象内存 */ json_object_put(parsed_json); printf("finish json parse\n"); } return 0; } /* 回调函数,用于获取HTTP响应码 */ static int check_response(void *clientp, curl_infotype type, char *buffer, size_t size) { /* 暂时不需要响应码,屏蔽掉 */ #if 0 int response_code = 0; if (type == CURLINFO_RESPONSE_CODE) { response_code = *((int *)clientp); } #endif return 0; } /* 下载天气的json数据 */ int download_weather_json_data(void) { CURL *curl; CURLcode res; FILE *fp; curl = curl_easy_init(); if (curl) { fp = fopen(outfilename, "wb"); if (!fp) { printf("Error opening file\n"); return 1; } curl_easy_setopt(curl, CURLOPT_URL, weather_URL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); // 使用默认的写入函数 curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // 将文件指针传递给写入函数 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, NULL); // 不需要处理头部信息 curl_easy_setopt(curl, CURLOPT_HEADERDATA, NULL); // 不需要传递头部数据 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 不验证SSL证书(不安全,仅用于演示) curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, check_response); // 设置调试回调函数,用于获取HTTP响应码 res = curl_easy_perform(curl); // 发送请求并下载文件 if (res != CURLE_OK) { printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); fclose(fp); // 关闭文件指针 return 1; } else { printf("success download weather json data\n"); fclose(fp); // 关闭文件指针。 } curl_easy_cleanup(curl); // 清理资源 } else { printf("curl_easy_init() failed\n"); return 1; } return 0; } /* 获取天气数据并刷新 */ void get_weather_data_and_refresh(GtkWidget *widget) { char weather_string[50]; int result; /* 获取天气JSON数据 */ result = download_weather_json_data(); /* 解析天气JSON数据 */ if (result == 1) { /* 下载天气json数据失败,显示对应的文本 */ sprintf(weather_string, "fail to download weather data"); gtk_label_set_text(GTK_LABEL(widget), weather_string); } else { sprintf(weather_string, "success to download weather data"); parse_weather_json_data(weather_string); gtk_label_set_text(GTK_LABEL(widget), weather_string); } } /* 刷新按钮回调函数,按钮被按下时调用 */ void button_refresh_clicked_cb(GtkButton *button, GtkWidget *widget) { gtk_label_set_text(GTK_LABEL(widget), "get weather data ......"); get_weather_data_and_refresh(widget); } /* mian函数 */ int main(int argc, char *argv[]) { /* 初始化GTK */ gtk_init(&argc, &argv); #if LOAD_UI_FROM_FILE /* 从ui文件加载界面布局 */ GtkBuilder *builder = gtk_builder_new(); GError *error = NULL; gtk_builder_add_from_file (builder, "/usr/local/ui.ui", &error); if (error != NULL) { printf("error: fail to load UI file: %s\n", error->message); g_error_free(error); return 1; } #endif /* 创建窗口 */ #if LOAD_UI_FROM_FILE GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); if (window == NULL) { printf("error: get object window fail\n"); } #else GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); #endif /* 设置窗口标签 */ gtk_window_set_title (GTK_WINDOW (window), "Clock and Weather Forecast"); /* 设置窗口的最小大小 */ gtk_widget_set_size_request(window, 400, 250); /* 绑定窗口的X,可以从触摸屏关闭整个程序 */ g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); #if !LOAD_UI_FROM_FILE #if (BOX_OR_GRID == BOX) /* 创建一个box,后续的控件都放box中 */ GtkWidget *box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20); /* 把box放到window中 */ gtk_container_add(GTK_CONTAINER(window), box1); #elif (BOX_OR_GRID == GRID) /* 创建一个grid,后续的控件都放grid中 */ GtkWidget *grid = gtk_grid_new (); /* 把grid放到window中 */ gtk_container_add (GTK_CONTAINER (window), grid); #endif #endif /* 创建一个标签,用于显示时间 */ #if LOAD_UI_FROM_FILE GtkWidget *label_timer = GTK_WIDGET(gtk_builder_get_object(builder, "label_timer")); #else GtkWidget *label_timer = gtk_label_new("waiting for get sys time"); #if (BOX_OR_GRID == BOX) /* 把标签放进box中 */ gtk_box_pack_start(GTK_BOX(box1), label_timer, FALSE, FALSE, 0); #elif (BOX_OR_GRID == GRID) /* 把标签放进grid中 */ gtk_grid_attach (GTK_GRID (grid), label_timer, 0, 0, 3, 1); #endif #endif /* 创建一个标签,用于天气信息 */ #if LOAD_UI_FROM_FILE GtkWidget *label_weather = GTK_WIDGET(gtk_builder_get_object(builder, "label_weather")); #else GtkWidget *label_weather = gtk_label_new("waiting for get weather forecast information"); #if (BOX_OR_GRID == BOX) /* 把标签放进box中 */ gtk_box_pack_start(GTK_BOX(box1), label_weather, FALSE, FALSE, 0); #elif (BOX_OR_GRID == GRID) /* 把标签放进grid中 */ gtk_grid_attach (GTK_GRID (grid), label_weather, 0, 1, 1, 1); #endif #endif /* 创建一个button,用于手动刷新天气信息 */ #if LOAD_UI_FROM_FILE GtkWidget *button_refresh = GTK_WIDGET(gtk_builder_get_object(builder, "button_refresh")); #else GtkWidget *button_refresh = gtk_button_new_with_label(refresh); // gtk_widget_set_size_request(button_refresh, 50, 20); #if (BOX_OR_GRID == BOX) /* 把button放进box中 */ gtk_box_pack_start(GTK_BOX(box1), button_refresh, FALSE, FALSE, 0); #elif (BOX_OR_GRID == GRID) /* 把标签放进grid中 */ gtk_grid_attach (GTK_GRID (grid), button_refresh, 3, 1, 1, 1); #endif #endif /* 设置回调函数 */ g_signal_connect(button_refresh, "clicked", G_CALLBACK(button_refresh_clicked_cb), label_weather); /* 创建一个button,用于退出程序 */ #if LOAD_UI_FROM_FILE GtkWidget *button_quit = GTK_WIDGET(gtk_builder_get_object(builder, "button_quit")); #else GtkWidget *button_quit = gtk_button_new_with_label("quit"); // gtk_widget_set_size_request(button_quit, 50, 20); #if (BOX_OR_GRID == BOX) /* 把button放进box中 */ gtk_box_pack_start(GTK_BOX(box1), button_quit, FALSE, FALSE, 0); #elif (BOX_OR_GRID == GRID) /* 把标签放进grid中 */ gtk_grid_attach (GTK_GRID (grid), button_quit, 3, 3, 1, 1); #endif #endif /* 设置回调函数 */ g_signal_connect(button_quit, "clicked", G_CALLBACK (gtk_main_quit), NULL); /* 把刚才创建的窗口显示出来 */ gtk_widget_show_all(window); #if FULLSCREEN /* 全屏显示 */ gtk_window_fullscreen(GTK_WINDOW(window)); #endif /* 创建定时器,每隔1s刷新时间 */ g_timeout_add(1000, (GSourceFunc)update_time, label_timer); /* 创建定时器,等时间到了,不再运行定时器。用于首次上电后更新天气数据。如果在这里直接更新,一旦下载或解析有问题,GTK界面会出来的很慢 */ g_timeout_add(1000, (GSourceFunc)first_run_update_weather, label_weather); /* 创建定时器,30min定时更新一次天气数据 */ g_timeout_add(1800000, (GSourceFunc)update_weather, label_weather); gtk_main(); #if LOAD_UI_FROM_FILE g_object_unref(builder); #endif return 0; } 配套的Makefile PROG = gtk_time SRCS = gtk_time.c CLEANFILES = $(PROG) # Add / change option in CFLAGS and LDFLAGS CFLAGS += -Wall $(shell pkg-config --cflags gtk+-3.0) LDFLAGS += $(shell pkg-config --libs gtk+-3.0) CFLAGS += -I/path/to/curl/include LDFLAGS += -L/path/to/curl/lib -lcurl LDFLAGS += -L/path/to/json-c/lib -ljson-c all: $(PROG) $(PROG): $(SRCS) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) clean: rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) 对应的ui.ui文件代码 <?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.22.2 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkWindow" id="window"> <property name="can_focus">False</property> <child type="titlebar"> <placeholder/> </child> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label_timer"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">waiting for get sys time</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="padding">32</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkLabel" id="label_weather"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">center</property> <property name="valign">center</property> <property name="margin_left">38</property> <property name="label" translatable="yes">waiting for get weather forecast information</property> <property name="justify">center</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkButton" id="button_refresh"> <property name="label" translatable="yes">refresh</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="pack_type">end</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="padding">41</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkButton" id="button_quit"> <property name="label" translatable="yes">quit</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="margin_left">170</property> <property name="margin_right">170</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> </object> </child> </object> </interface> 界面显示如下   这个代码写的界面有以下几种配置方式 ①是否全屏显示,修改FULLSCREEN宏定义 ②界面布局是否从UI文件加载,如果是,那么就需要把上面的ui.ui文件也放到135中,我代码中写的路径是/usr/local/。修改LOAD_UI_FROM_FILE宏定义 ③不使用UI文件的情况下,使用BOX布局还是GRID布局,修改BOX_OR_GRID。这是我前期探索时,手动制作的界面布局   最终版的配置参数是全屏+使用UI加载   详细的代码我就不解读了,我写了非常详细的注释。   运行demo步骤如下,在ubuntu中编译好代码,将执行文件和ui.ui放到135的/usr/local下,修改两个文件的权限,然后运行 chmod 777 ui.ui chmod 777 gtk_time su -l weston -c "/usr/local/gtk_time"   我这里要说一下ui.ui文件是怎么来的,手动绘制界面真的非常麻烦,效率也很低,我在网上搜索到一个好东西“Glade”,他只管绘制界面,有点类似前端后端分离的感觉,他最终会生产一个文件,然后GTK加载这文件,就可以直接显示出绘制的界面,这个软件需要在ubuntu中运行(win貌似也可以,但是我没有找到对应的安装包),在ubuntu中安装只需要使用以下命令 sudo apt-get install glade 安装好后就有一个Glade应用程序的图标,点击即可运行(下图是我绘制的界面) 这个软件我就不细讲了,大家可以自行摸索,总的来说还是很容易上手的,我大约捣鼓了十来分钟就基本上手了 绘制好后,点击save,默认的文件扩展名是“.glade”,其实就是xml,可以手动修改后缀,然后就可以使用了(给到135后还要修改一下文件的权限,保证他可以被读取)   最后放一段演示视频 [localvideo]8351d3844db6f4ba7218b2422b983699[/localvideo]  

  • 发表了主题帖: [STM32MP135F-DK]测评 ⑦MP135 GTK与中文

    本帖最后由 不爱胡萝卜的仓鼠 于 2023-12-26 13:32 编辑        写在最前面:我没有解决在MP135上使用GTK绘制的界面如何显示中文的问题,但是我找到了一些方向,只是不知道该如何操作           我绘制了一个界面,放置了一个标签,标签上写“刷新”,标签的代码如下 GtkWidget *label = gtk_label_new("刷新"); 但是界面显示的是一串乱码,如下图所示 于是我就去网上找GTK显示中文的帖子,基本上都是说中文编码的问题,GTK只认UTF-8,需要在代码中加入转换函数,转成UTF-8编码。我也照做了,没有用。 我就怀疑是不是转换函数没有生效,我就直接手动把中文转换成TUF-8编码   装进数组里,直接把数据给GTK(下面放了部分代码,我把“刷新”放到一个按钮上) char refresh[] = {0x52, 0x37, 0x65, 0xB0, '\0'}; GtkWidget *button_refresh = gtk_button_new_with_label(refresh); 结果SSH界面还多了报错 (gtk_time:1955): Pango-WARNING **: 22:43:01.956: Invalid UTF-8 string passed to pango_layout_set_text() 说我给的不是UTF-8,哦那就有意思了,应该是我直接塞数组的动作有错,但是这也侧面反映了,之前我直接在代码中给中文是正确的。 突然我发现,一开始的界面上现实的乱码其实就是UTF-8的编码,所以我得出一个结论:代码和编译方式都是正确的,但是135上没有对用的中文字库,所以无法显示中文字符。 为了验证我的猜想,我突然想到之前测试时写了一个printf当前时间的demo,打印出的内容中就有中文,在SSH中是可以正常显示出来的,在SSH中运行的结果如下 于是我给135插上键盘,运行之前的程序,如下图所示 同样的代码,结果不同,那么我就可以断定,就是135上缺少对应的中文字库。   但是到此为止我已经不知道该怎么下一步了,方向很明确要给他装一个中文字库,但是我就是不知道怎么装,如果有知道该怎么做的大佬,欢迎在评论区指导一下。所以后面我制作demo时只能避开中文了  

  • 2023-12-23
  • 回复了主题帖: [STM32MP135F-DK]测评 ②烧录一个新系统

    Tristan_C 发表于 2023-12-21 10:01 你的启动连上会出现电源提示电流500mA吗?     我的液晶没亮起来,烧写的时候也没亮起 ... 你的供电有问题,电源要5V3A的规格,你的电源输出电流太小带不动开发板

  • 2023-12-17
  • 发表了主题帖: [STM32MP135F-DK]测评 ⑥自动网络校时+获取天气信息

    本帖最后由 不爱胡萝卜的仓鼠 于 2023-12-17 19:19 编辑         本篇对应的是测评计划中的网络相关测评,本来想着学习一下网络相关的驱动啥的,但是ST已经做好了,我到手插上网线就可以用,那我就为最终demo做一下网络相关的前期工作   1.自动网络校时         自从我拿到开发板后,每次使用shutdown命令,系统给我的时间都是错误的,搞得我很难受。用手动校准吧,因为没有整上RTC电池,一关机断电,时间就不会更新了,那我还是得整一下自动校时         同时参与135评测的其他朋友已经做了自动校时的内容,链接在此(https://bbs.eeworld.com.cn/thread-1267051-1-1.html#pid3286979),给我提供了很多参考         首先修改一下ntp的配置文件,mobaxterm编辑文件很方便,直接双击就可以打开编辑,不用在终端使用vim。配置文件在/etc/ntp.conf 在图中位置加入这句话,告诉ntp应该去那个地址获取时间信息   server cn.pool.ntp.org prefer cn.pool.ntp.org是ntp网络授时组织的中国授时源         修改完配置文件后,重启NTP systemctl restart ntpd 过一会儿就会自动更新时间了         但是过一会儿时间更新后,日期对了,时间还是错的,用 timedatectl 命令看了一下,是时区还没有设置,还是默认的格林威治时间(UTC+0) 用 timedatectl list-timezones 命令查看一下所有可供选择的时区 root@stm32mp1:~# timedatectl list-timezones Africa/Abidjan Africa/Algiers Africa/Bissau Africa/Cairo Africa/Casablanca Africa/Ceuta Africa/El_Aaiun Africa/Johannesburg Africa/Juba Africa/Khartoum Africa/Lagos Africa/Maputo Africa/Monrovia Africa/Nairobi Africa/Ndjamena Africa/Sao_Tome Africa/Tripoli Africa/Tunis Africa/Windhoek America/Adak America/Anchorage America/Araguaina America/Argentina/Buenos_Aires America/Argentina/Catamarca America/Argentina/Cordoba America/Argentina/Jujuy America/Argentina/La_Rioja America/Argentina/Mendoza America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Asuncion America/Bahia America/Bahia_Banderas America/Barbados America/Belem America/Belize America/Boa_Vista America/Bogota America/Boise America/Cambridge_Bay America/Campo_Grande America/Cancun America/Caracas America/Cayenne America/Chicago America/Chihuahua America/Ciudad_Juarez America/Costa_Rica America/Cuiaba America/Danmarkshavn America/Dawson America/Dawson_Creek America/Denver America/Detroit America/Edmonton America/Eirunepe America/El_Salvador America/Fort_Nelson America/Fortaleza America/Glace_Bay America/Goose_Bay America/Grand_Turk America/Guatemala America/Guayaquil America/Guyana America/Halifax America/Havana America/Hermosillo America/Indiana/Indianapolis America/Indiana/Knox America/Indiana/Marengo America/Indiana/Petersburg America/Indiana/Tell_City America/Indiana/Vevay America/Indiana/Vincennes America/Indiana/Winamac America/Inuvik America/Iqaluit America/Jamaica America/Juneau America/Kentucky/Louisville America/Kentucky/Monticello America/La_Paz America/Lima America/Los_Angeles America/Maceio America/Managua America/Manaus America/Martinique America/Matamoros America/Mazatlan America/Menominee America/Merida America/Metlakatla America/Mexico_City America/Miquelon America/Moncton America/Monterrey America/Montevideo America/New_York America/Nome America/Noronha America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem America/Nuuk America/Ojinaga America/Panama America/Paramaribo America/Phoenix America/Port-au-Prince America/Porto_Velho America/Puerto_Rico America/Punta_Arenas America/Rankin_Inlet America/Recife America/Regina America/Resolute America/Rio_Branco America/Santarem America/Santiago America/Santo_Domingo America/Sao_Paulo America/Scoresbysund America/Sitka America/St_Johns America/Swift_Current America/Tegucigalpa America/Thule America/Tijuana America/Toronto America/Vancouver America/Whitehorse America/Winnipeg America/Yakutat Antarctica/Casey Antarctica/Davis Antarctica/Macquarie Antarctica/Mawson Antarctica/Palmer Antarctica/Rothera Antarctica/Troll Asia/Almaty Asia/Amman Asia/Anadyr Asia/Aqtau Asia/Aqtobe Asia/Ashgabat Asia/Atyrau Asia/Baghdad Asia/Baku Asia/Bangkok Asia/Barnaul Asia/Beirut Asia/Bishkek Asia/Chita Asia/Choibalsan Asia/Colombo Asia/Damascus Asia/Dhaka Asia/Dili Asia/Dubai Asia/Dushanbe Asia/Famagusta Asia/Gaza Asia/Hebron Asia/Ho_Chi_Minh Asia/Hong_Kong Asia/Hovd Asia/Irkutsk Asia/Jakarta Asia/Jayapura Asia/Jerusalem Asia/Kabul Asia/Kamchatka Asia/Karachi Asia/Kathmandu Asia/Khandyga Asia/Kolkata Asia/Krasnoyarsk Asia/Kuching Asia/Macau Asia/Magadan Asia/Makassar Asia/Manila Asia/Nicosia Asia/Novokuznetsk Asia/Novosibirsk Asia/Omsk Asia/Oral Asia/Pontianak Asia/Pyongyang Asia/Qatar Asia/Qostanay Asia/Qyzylorda Asia/Riyadh Asia/Sakhalin Asia/Samarkand Asia/Seoul Asia/Shanghai Asia/Singapore Asia/Srednekolymsk Asia/Taipei Asia/Tashkent Asia/Tbilisi Asia/Tehran Asia/Thimphu Asia/Tokyo Asia/Tomsk Asia/Ulaanbaatar Asia/Urumqi Asia/Ust-Nera Asia/Vladivostok Asia/Yakutsk Asia/Yangon Asia/Yekaterinburg Asia/Yerevan Atlantic/Azores Atlantic/Bermuda Atlantic/Canary Atlantic/Cape_Verde Atlantic/Faroe Atlantic/Madeira Atlantic/South_Georgia Atlantic/Stanley Australia/Adelaide Australia/Brisbane Australia/Broken_Hill Australia/Darwin Australia/Eucla Australia/Hobart Australia/Lindeman Australia/Lord_Howe Australia/Melbourne Australia/Perth Australia/Sydney Europe/Andorra Europe/Astrakhan Europe/Athens Europe/Belgrade Europe/Berlin Europe/Brussels Europe/Bucharest Europe/Budapest Europe/Chisinau Europe/Dublin Europe/Gibraltar Europe/Helsinki Europe/Istanbul Europe/Kaliningrad Europe/Kirov Europe/Kyiv Europe/Lisbon Europe/London Europe/Madrid Europe/Malta Europe/Minsk Europe/Moscow Europe/Paris Europe/Prague Europe/Riga Europe/Rome Europe/Samara Europe/Saratov Europe/Simferopol Europe/Sofia Europe/Tallinn Europe/Tirane Europe/Ulyanovsk Europe/Vienna Europe/Vilnius Europe/Volgograd Europe/Warsaw Europe/Zurich Indian/Chagos Indian/Maldives Indian/Mauritius Pacific/Apia Pacific/Auckland Pacific/Bougainville Pacific/Chatham Pacific/Easter Pacific/Efate Pacific/Fakaofo Pacific/Fiji Pacific/Galapagos Pacific/Gambier Pacific/Guadalcanal Pacific/Guam Pacific/Honolulu Pacific/Kanton Pacific/Kiritimati Pacific/Kosrae Pacific/Kwajalein Pacific/Marquesas Pacific/Nauru Pacific/Niue Pacific/Norfolk Pacific/Noumea Pacific/Pago_Pago Pacific/Palau Pacific/Pitcairn Pacific/Port_Moresby Pacific/Rarotonga Pacific/Tahiti Pacific/Tarawa Pacific/Tongatapu UTC   设置一下时区为上海 timedatectl set-timezone Asia/Shanghai 再重新重启一下NTP,时间终于正确了   2.获取天气信息         天气信息我这边使用的是知心天气,他可以免费试用,网址如下:https://www.seniverse.com/         怎么注册账号、登录我就不说了,登录后之间点击免费使用 然后选择这个免费的 然后就可以得到一个公钥和私钥 直接访问下面的网址就可以得到json的天气数据 https://api.seniverse.com/v3/weather/now.json?key=私钥&location=城市编码 其中私钥文本要更换成刚才得到的私钥,城市编码可以在以下网址得到:https://docs.seniverse.com/api/start/start.html 点击下载的到一个excel,找到对应的城市,我这边以杭州为例 直接在浏览器中输入刚才的网址,得到对应的json信息 现在确定了,这个天气信息是可以得到的,现在去135上试试 使用 curl -X GET "网址" 命令就可以拉下来天气的json数据 OK,可以拉下来

  • 回复了主题帖: 【STM32MP135F-DK】4-自动校时和手动校时

    修改时区的命令应该是 timedatectl set-timezone Asia/Shanghai  

  • 回复了主题帖: 【STM32MP135F-DK】4-自动校时和手动校时

    重启ntpd服务中的指令错啦,应该是 systemctl restart ntpd  

  • 2023-12-16
  • 发表了主题帖: [STM32MP135F-DK]测评 ⑤点灯

    本帖最后由 不爱胡萝卜的仓鼠 于 2023-12-17 15:13 编辑         上周helloworld成功跑起来了,这周来整一下GPIO,说到GPIO那就必须得是经典的点亮一个LED灯。           但是从单片机转到linux,想点个灯就没有那么简单了,在单片机中就直接配置寄存器,如果用STM32的直接在cubemx中图形化配置,完成外设的初始化,然后调用对应控制GPIO的函数即可。但是在linux中就没有那么简单了,所以我找了半天的资料,最终兜兜转转还是回到了ST的wiki, 不得不说,ST在资料方面做的真是不错,像我这样没有原厂FEA支持的开发者,也可以通过公开释放的资料,进行学习开发,当然ST也有论坛,不过我没有去提问过。好了言归正传,开始今日的点灯           首先我把对应的wiki连接放这里(https://wiki.stmicroelectronics.cn/stm32mpu/wiki/Overview_of_GPIO_pins),这一页简单介绍了135关于引脚配置和控制的Linux内核框架,如下图所示 从图中我们可以看到,135的引脚控制只有3个,irqchip、pinctrl、GPIOlib。其中irqchip听名字就知道是管中断的,不在今天点灯的范畴里,我就不看了。另外两个都可以管GPIO,但是他俩各有特点,我就直接把ST的原文借过来了   可以使用两个框架来配置和控制给定的引脚:pinctrl 和 GPIOLib。它们是根据引脚使用情况选择的: Pinctrl 主要用于引脚由内部外设控制的情况。Pinctrl 处理引脚配置,并允许将特定功能分配给引脚。Pinctrl 概述一文提供了 pinctrl 框架的概述。 GPIOLib 用于需要在运行时动态控制引脚 (GPIO) 的情况。GPIOLib 用于通过软件控制引脚。GPIOLib 概述一文概述了 GPIOLib           今天我就尝试一下GPIOlib,看框图它是用户层的代码可以直接通过char device控制GPIOlib,从而控制GPIO,感觉和单片机的玩法有点像,那么就要跳转去讲GPIOlib的wiki页面,连接如下https://wiki.stmicroelectronics.cn/stm32mpu/wiki/How_to_control_a_GPIO_in_userspace   这个页面中讲了通过命令和程序控制LED灯 我先试试命令 1.检测命令 gpiodetect 2.信息命令 gpioinfo  这里信息还挺多的,我就不截图了,直接上终端的内容 root@stm32mp1:~# gpioinfo gpiochip0 - 16 lines: line 0: "PA0" input line 1: "PA1" input consumer="kernel" line 2: "PA2" input consumer="kernel" line 3: "PA3" input consumer="kernel" line 4: "PA4" input line 5: "PA5" input line 6: "PA6" input consumer="kernel" line 7: "PA7" input line 8: "PA8" input line 9: "PA9" input consumer="kernel" line 10: "PA10" input line 11: "PA11" input line 12: "PA12" input consumer="kernel" line 13: "PA13" input active-low bias=pull-up consumer="User-PA13" line 14: "PA14" output active-low consumer="blue:heartbeat" line 15: "PA15" input consumer="kernel" gpiochip1 - 16 lines: line 0: "PB0" input line 1: "PB1" input line 2: "PB2" input consumer="kernel" line 3: "PB3" input consumer="kernel" line 4: "PB4" input consumer="kernel" line 5: "PB5" input line 6: "PB6" input consumer="kernel" line 7: "PB7" input consumer="kernel" line 8: "PB8" input consumer="kernel" line 9: "PB9" input consumer="kernel" line 10: "PB10" input line 11: "PB11" input consumer="kernel" line 12: "PB12" input consumer="kernel" line 13: "PB13" input line 14: "PB14" input consumer="kernel" line 15: "PB15" input consumer="kernel" gpiochip2 - 16 lines: line 0: "PC0" input line 1: "PC1" input consumer="kernel" line 2: "PC2" input line 3: "PC3" input line 4: "PC4" input consumer="kernel" line 5: "PC5" input consumer="kernel" line 6: "PC6" input consumer="kernel" line 7: "PC7" input consumer="kernel" line 8: "PC8" input consumer="kernel" line 9: "PC9" input consumer="kernel" line 10: "PC10" input consumer="kernel" line 11: "PC11" input consumer="kernel" line 12: "PC12" input consumer="kernel" line 13: "PC13" input line 14: "PC14" input line 15: "PC15" input gpiochip3 - 16 lines: line 0: "PD0" input consumer="kernel" line 1: "PD1" input consumer="kernel" line 2: "PD2" input consumer="kernel" line 3: "PD3" input consumer="kernel" line 4: "PD4" input consumer="kernel" line 5: "PD5" input consumer="kernel" line 6: "PD6" input consumer="kernel" line 7: "PD7" input consumer="kernel" line 8: "PD8" input consumer="kernel" line 9: "PD9" input consumer="kernel" line 10: "PD10" input consumer="kernel" line 11: "PD11" input consumer="kernel" line 12: "PD12" input consumer="kernel" line 13: "PD13" input line 14: "PD14" input consumer="kernel" line 15: "PD15" input consumer="kernel" gpiochip4 - 16 lines: line 0: "PE0" input consumer="kernel" line 1: "PE1" input line 2: "PE2" input consumer="kernel" line 3: "PE3" input consumer="kernel" line 4: "PE4" input consumer="kernel" line 5: "PE5" input line 6: "PE6" input line 7: "PE7" input consumer="kernel" line 8: "PE8" input consumer="kernel" line 9: "PE9" input consumer="kernel" line 10: "PE10" input line 11: "PE11" input consumer="kernel" line 12: "PE12" output consumer="panel-backlight" line 13: "PE13" input consumer="kernel" line 14: "PE14" input consumer="kernel" line 15: "PE15" input consumer="kernel" gpiochip5 - 16 lines: line 0: "PF0" input consumer="interrupt" line 1: "PF1" input consumer="kernel" line 2: "PF2" input consumer="kernel" line 3: "PF3" input consumer="kernel" line 4: "PF4" input consumer="kernel" line 5: "PF5" input consumer="interrupt" line 6: "PF6" input consumer="kernel" line 7: "PF7" input consumer="kernel" line 8: "PF8" input line 9: "PF9" input line 10: "PF10" input line 11: "PF11" input line 12: "PF12" input consumer="kernel" line 13: "PF13" input line 14: "PF14" input line 15: "PF15" input gpiochip6 - 16 lines: line 0: "PG0" input consumer="kernel" line 1: "PG1" input line 2: "PG2" input consumer="kernel" line 3: "PG3" input line 4: "PG4" input consumer="kernel" line 5: "PG5" input consumer="kernel" line 6: "PG6" input consumer="kernel" line 7: "PG7" input consumer="kernel" line 8: "PG8" input consumer="kernel" line 9: "PG9" input consumer="kernel" line 10: "PG10" input consumer="kernel" line 11: "PG11" input consumer="kernel" line 12: "PG12" input consumer="interrupt" line 13: "PG13" input consumer="kernel" line 14: "PG14" input consumer="kernel" line 15: "PG15" input gpiochip7 - 15 lines: line 0: "PH0" input line 1: "PH1" input line 2: "PH2" output active-low consumer="reset" line 3: "PH3" input line 4: "PH4" input active-low bias=pull-up consumer="cd" line 5: "PH5" input line 6: "PH6" input consumer="kernel" line 7: "PH7" input line 8: "PH8" input consumer="kernel" line 9: "PH9" input consumer="kernel" line 10: "PH10" input line 11: "PH11" input line 12: "PH12" input consumer="kernel" line 13: "PH13" input consumer="kernel" line 14: "PH14" input consumer="kernel" gpiochip8 - 8 lines: line 0: "PI0" input line 1: "PI1" input consumer="kernel" line 2: "PI2" input consumer="kernel" line 3: "PI3" input consumer="kernel" line 4: "PI4" input line 5: "PI5" input line 6: "PI6" input line 7: "PI7" output consumer="enable" gpiochip9 - 16 lines: line 0: unnamed input line 1: unnamed input line 2: unnamed output active-low consumer=reset line 3: unnamed output line 4: unnamed output line 5: unnamed input line 6: unnamed input line 7: unnamed input line 8: unnamed input line 9: unnamed output active-low consumer=PHY reset line 10: unnamed output active-low consumer=PHY reset line 11: unnamed output active-low consumer=reset line 12: unnamed input line 13: unnamed output consumer=shutdown line 14: unnamed input line 15: unnamed input   3.get命令 我是点灯,属于输出,不要输入,get命令我就不尝试了,有兴趣的去wiki自行阅读   4.set命令 之前开箱篇说了LED3是linux的心跳灯,那我就用LED4,对应的是PA13 啊?怎么回事?busy? 经过一顿排查,原来这个灯已经被用掉了,看info中就可以看到,被“User-PA13”用了,但是我不知道我该怎么让他释放对这个灯的占用,没办法,板子上还有2个灯,通过MCP拓展出去的,随便选一个试试 gpioset -c gpiochip9 14=1 成功!灯亮了 再试试闪烁 gpioset -t 500ms -c gpiochip9 14=active [localvideo]81432dfb49df4806e2bcaf4637cb1815[/localvideo]           再来试试用代码,wiki页面中使用的是PA14,这个引脚不能再用了,那我还得改造一下代码,刚才命令试了LED7,现在换成LED6的。具体的编译、下载、运行啥的我这边就不赘述了,可以参照看上一篇helloworld .c如下 #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <linux/gpio.h> int main(int argc, char **argv) { struct gpiohandle_request req; struct gpiohandle_data data; char chrdev_name[20]; int fd, ret; strcpy(chrdev_name, "/dev/gpiochip9"); /* Open device: gpiochip9 for GPIO MCP */ fd = open(chrdev_name, 0); if (fd == -1) { ret = -errno; fprintf(stderr, "Failed to open %s\n", chrdev_name); return ret; } /* request GPIO line: GPIO_9_15 */ req.lineoffsets[0] = 15; req.flags = GPIOHANDLE_REQUEST_OUTPUT; memcpy(req.default_values, &data, sizeof(req.default_values)); strcpy(req.consumer_label, "led_gpio_mcp_15"); req.lines = 1; ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n", ret); } if (close(fd) == -1) perror("Failed to close GPIO character device file"); /* Start led blinking */ while(1) { data.values[0] = !data.values[0]; ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue %s (%d)\n", "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret); } sleep(1); } /* release line */ ret = close(req.fd); if (ret == -1) { perror("Failed to close GPIO LINEHANDLE device file"); ret = -errno; } return ret; } makeflie如下 PROG = led SRCS = led.c OBJS = $(SRCS:.c=.o) CLEANFILES = $(PROG) # Add / change option in CFLAGS if needed # CFLAGS += <new option> $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) .c.o: $(CC) $(CFLAGS) -c $< -o $@ all: $(PROG) clean: rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ 看看效果 [localvideo]9f60dc7cb4674a3de6a8abd25c6a3da1[/localvideo]   好了,点灯篇结束

  • 2023-12-10
  • 发表了主题帖: [STM32MP135F-DK]测评 ④安装SDK及HelloWorld

    本帖最后由 不爱胡萝卜的仓鼠 于 2023-12-11 17:01 编辑   今天来整一个HelloWorld,这下就必须要使用Ubuntu了,我用的一个虚拟机,Ubuntu 20.04   一、安装SDK         安装SDK在Ubuntu虚拟机中进行,首先安装额外的包 sudo apt-get update sudo apt-get install gawk wget git diffstat unzip texinfo gcc-multilib chrpath socat cpio python3 python3-pip python3-pexpect sudo apt-get install libssl-dev libgmp-dev libmpc-dev lz4 zstd sudo apt-get install build-essential libncurses-dev libyaml-dev libssl-dev   sudo apt-get install coreutils bsdmainutils sed curl bc lrzsz corkscrew cvs subversion mercurial nfs-common nfs-kernel-server libarchive-zip-perl dos2unix texi2html libxml2-utils 额外的配置 echo 'options mmc_block perdev_minors=16' > /tmp/mmc_block.conf sudo mv /tmp/mmc_block.conf /etc/modprobe.d/mmc_block.conf 下载SDK(SDK下载地址) 放到虚拟机中(在home路径下创建一个叫“STM32MPU_workspace”的文件夹,在这个文件夹下再创建一个名叫“tmp”的文件夹),解压 运行SDK安装脚本 创建一个文件夹 mkdir -p $HOME/STM32MPU_workspace/STM32MP1-Ecosystem-v5.0.0/Developer-Package/SDK 修改SDK安装脚本的权限,使其可执行  chmod +x stm32mp1-openstlinux-6.1-yocto-mickledore-mp1-v23.06.21/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-4.2.1-openstlinux-6.1-yocto-mickledore-mp1-v23.06.21.sh   执行SDK安装脚本 ./stm32mp1-openstlinux-6.1-yocto-mickledore-mp1-v23.06.21/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-4.2.1-openstlinux-6.1-yocto-mickledore-mp1-v23.06.21.sh -d /home/ubuntuadmin/STM32MPU_workspace/STM32MP1-Ecosystem-v5.0.0/Developer-Package/SDK   检查一下安装结果,在每次使用前都要source一下环境变量,如下 cd $HOME/STM32MPU_workspace/STM32MP1-Ecosystem-v5.0.0/Developer-Package source SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi 检查目标体系结构  echo $ARCH  检查toolchain echo $CROSS_COMPILE 检查C编译器的版本 $CC --version 检查SDK版本  echo $OECORE_SDK_VERSION   二、HelloWorld 创建一个存放源代码的目录 创建一个存放helloworld代码的文件夹 mkdir $HOME/STM32MPU_workspace/STM32MP1-Ecosystem-v5.0.0/Developer-Package/stm32mp1-openstlinux-23.06.21/sources/gtk_hello_world_example cd $HOME/STM32MPU_workspace/STM32MP1-Ecosystem-v5.0.0/Developer-Package/stm32mp1-openstlinux-23.06.21/sources/gtk_hello_world_example   然后创建两个文件,一个.c、一个Makeflie   然后在终端中直接输入make,完了有error,提示找不到gtk.h(图中路径请忽略,这是之前的截图) 那我得装一下gtk,这里特别注意,要装GTK3,不要装2.0(图中路径请忽略,这是之前的截图) 再次make,这次不报这个错误了,换别的了(图中路径请忽略,这是之前的截图) 不管了,听报错的,我改,改了2次,就可以编译通过了(图中路径请忽略,这是之前的截图) 得到的编译结果(图中路径请忽略,这是之前的截图) 把这个文件从虚拟机中拷贝到win,再通过SSH放到135的/usr/local/ 路径下   然后在终端中,输入命令运行helloworld su -l weston -c "/usr/local/gtk_hello_world" 报错没有权限,看一下我对这个文件的权限 ls -l 修改一下权限 再次运行 完蛋,一堆乱码   经过一段时间的摸索,我找到了原因,还记得在SDK安装时有一句话吗?“在每次使用前都要source一下环境变量”,在打开一个终端后,要编译代码,就要先在终端source一下环境变量,然后在cd到代码路径,再make 终于,可以成功运行了   [localvideo]1cc36750f3f51d50330bafd10cff8016[/localvideo]   最后贴一下.c和Makefile中的内容 #include <gtk/gtk.h> static void print_hello (GtkWidget *widget, gpointer data) { g_print ("Hello World\n"); } static void activate (GtkApplication *app, gpointer user_data) { GtkWidget *window; GtkWidget *button; GtkWidget *button_box; window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Window"); gtk_window_set_default_size (GTK_WINDOW (window), 200, 200); button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); gtk_container_add (GTK_CONTAINER (window), button_box); button = gtk_button_new_with_label ("Hello World"); g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window); gtk_container_add (GTK_CONTAINER (button_box), button); gtk_widget_show_all (window); } int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("org.gtk.example", G_APPLICATION_REPLACE); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }   PROG = gtk_hello_world SRCS = gtk_hello_world.c CLEANFILES = $(PROG) # Add / change option in CFLAGS and LDFLAGS CFLAGS += -Wall $(shell pkg-config --cflags gtk+-3.0) LDFLAGS += $(shell pkg-config --libs gtk+-3.0) all: $(PROG) $(PROG): $(SRCS) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) clean: rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))  

  • 发表了主题帖: [STM32MP135F-DK]测评 ③串口终端与SSH

    本帖最后由 不爱胡萝卜的仓鼠 于 2023-12-10 01:27 编辑         今天来整一下串口终端与SSH,为后续的开发做好准备         在前面的开箱篇中我可以使用USB键鼠,在开发板上直接运行一个终端,但是在开发板上使用终端实在是太麻烦了,所以今天整一下在Win电脑上使用终端,顺便把SSH也整一下(用于后续传输文件和SSH挂到VScode上写代码)         Win电脑端我使用的是MobaXterm 一、串口终端         MP135的有一个串口连接到开发板上的ST-LINK上,这个串口就是终端(就是之前烧录篇中说到的输出日志的那个串口),使用起来很简单,只需要将ST-Link通过USB线连接电脑即可(ST-Link的驱动要提前装一下),然后给开放板上电。接线如下图所示 在Moba中我们点击左上角的Session 然后选择Serial(串口),需要注意的是,ST-Link会有2个串口,需要选择名称结尾是Port的,而不是Port 2。波特率115200 连接成功后,就可以看到终端了。这里再说一下账号的情况,进入默认的账号是root,没有密码   这里随便输入个命令看看,可以正常使用   二、SSH         SSH我这边使用网线,使用WiFi、还有上一篇那个烧录固件的USB口也是可以的。但是WiFi现在还没捣鼓明白,暂时先放弃。USB口的话,我测试了可以使用,会虚拟成一个网卡,但是我之前说了,我使用的是一个转接头,把MicroUSB转成Type-C,那玩意很不稳定,动一动就断。保险起见就直接使用网线是最好的,而且这样回头我还可以用手机或平板登录。         首先需要把网线与板卡连接,任意一个网口都可以。我的网线是直接从路由器中拉出来的,我的电脑、手机、平板也是连接的这个路由器,他们都在同一个局域网中(如果你没有路由器,理论上直接与电脑接也是可以的,但是这样的话使用就会有些限制,没有我这样自由)。接线如下图所示   此时,之前我们串口的终端会打印出一句话,大致意思就是网口被连接了,已经可以正常工作了 然后SSH需要知道板卡的IP地址,有2个方法,一个是登录路由器后台查看路由器给板卡分配的IP地址(这样操作比较麻烦,并且我还得根据板卡上贴的MAC去找,太麻烦);方法二就是直接在终端里使用ifconfig命令 这里我们可以看到,板子的网络一共有4个,2个ETH以太网网卡、1个lo(主机的回环网卡)、1个USB网卡。我这边连接的就是板子上的ETH1对应的就是这里的end0。这里的inet addr后面就是分配到的IP地址,回头SSH就使用这个地址         还是老样子,在Moba中我们点击左上角的Session 然后点击SSH,输入刚才的IP地址,点击OK即可 连接成功,进入登录界面   这边需要输入账号,就是之前说的root,没有密码。成功登录     在这里也可以使用终端,左边可以直接浏览整个Linux系统的文件系统,可以上传和下载文件,这边我就不细说了。

  • 2023-12-04
  • 回复了主题帖: [STM32MP135F-DK]测评 ②烧录一个新系统

    秦天qintian0303 发表于 2023-12-4 09:52 先在想用小卡都不好找了,每次启动都是从TF卡开始吗 是的,官方的这款开发板硬件上只设计了从TF启动,如果可以增加一个EMMC启动就好了,就算是预留焊盘也行啊

  • 2023-12-03
  • 发表了主题帖: [STM32MP135F-DK]测评 ②烧录一个新系统

            今天来学习一下开发环境搭建及程序烧录         所需准备:电脑(不限win或linux)、STM32CubeProgrammer软件、一张TF卡(原装的TF我不使用,保留,这样后续出问题还能使用原装TF做后备)                  我看了一下ST官方的wiki,里面使用的是ubuntu系统,但是我看操作步骤只是安装STM32CubeProgrammer、下载镜像(下载的就是预装demo的系统镜像)、下载。没有编译的步骤,所以我觉得linux系统不是必须的,因此本次烧录我使用win,这样就不需要再去搞虚拟机再安装软件。等下次需要使用linux编译的时候再去折腾           首先我们去下载镜像(链接:https://www.st.com/en/embedded-software/stm32mp1starter.html#get-software),这里下载如果你有注册账号,就可以登录后直接获取下载链接,下载。如果没有可以填你的邮箱,st会通过邮件方式发送下载链接。我推荐第一种,邮件有的时候他会过很久才发给你         下载好后解压         开发板上更换新的TF卡(我之前说了,我要保留原来的卡,万一后续如果操作有问题,还可以用原装卡来检验是板卡故障还是我系统制作有问题),这里TF卡我再多说一句,建议使用正规品牌的TF卡(因为会存在兼容性问题,我一开始用了一张杂牌的8G卡,会提示无法擦除,如下图所示),最好class 10的,容量不要太小(我直接使用和原厂一样的16G)           ST-Link接口接上USB线(可选,用于观察烧录过程中的日志,虽然系统进入U-Boot后屏幕也会显示日志)         左下角的Type-C口(CN7)是烧录用的USB-OTG,一定要使用一条质量好一点的Type-C数据线,不要像我使用MicroUSB+转接头,2.0的就可以了,我看了原理图,这个接口只支持USB2.0。这个数据线建议直接接到电脑的USB 3.0口上,不要使用机箱前面板或HUB。我因为这个口子、线材问题,经常出现烧录异常中断找不到USB设备、烧录慢等问题。         将Boot开关open侧全部按下,接口进入USB烧录模式,这里我就不放图了,具体可以看上一篇文章         然后打开STM32CubeProgrammer,给板卡上电/按一下复位键,右侧选择USB,即可看到“USB1”,如果看不到那就点一下刷新           然后点击connect,连接上板卡后可以在右下角看到板卡信息,然后点击“open file”         这里打开的是烧录脚本,烧录会分多次烧录多个文件,所以需要一个脚本指定烧录的先后顺序,每个文件的偏移量等信息 在官方的压缩包中有很多烧录脚本,属于135的只有一个,所以不需要仔细看,直接选择135的就可以,加载好后如下图所示 然后还需要指定一下Binaries path,如下图所示   然后点击Download即可   之后就会开始下载,之前讲过很分多次烧录多个文件们,在烧录完一个后USB就会断连再充连,不过这些步骤都是自动进行的,不需要人为干预,当进入U-Boot后,屏幕会亮起,将下载日志打印在屏幕上,同时也可以从ST-Link的的串口中看到日志(有两个串口,其中只有一个会打印,波特率115200),整个烧录过程大约会需要几分钟,具体我没有掐表计算过。在此期间不要动USB线,避免接触不良导致烧录失败         烧录成功后,会提示如图         随后就可以将BOOT开关拨回原样,让系统从TF卡启动。点击复位键,系统就可以启动了,需要注意的是,第一次启动会需要一些时间 ,显示ST界面后大约会黑屏几分钟,可能是内部在做一些初始化。启动成功后如图    

统计信息

已有42人来访过

  • 芯积分:157
  • 好友:--
  • 主题:9
  • 回复:12

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言