一,前言
上次blogQemu虚化HW相关—Apple的学习笔记已经分析了要修改qemu源码自定义开发板其实就是要看懂graphic.c,而里面用到的就是SDL2和其扩展库SDL2_Image扩展库,而我之前已经搭建了SLD2的mingw开发环境,并且在官网了解了SDL2的API看懂了graphic.c那么就开始修改为自定义开发板。
二,在SDL2中实现开发板LED闪烁界面
效果为按下鼠标后,右下角的LED灯颜色会变。
codeblocks源码如下:
#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
//Screen dimension constants
const int SCREEN_WIDTH = 346;
const int SCREEN_HEIGHT = 452;
typedef struct {
SDL_Renderer *renderer;
SDL_Window *window;
} App;
App app;
typedef struct {
int x;
int y;
SDL_Texture *texture;
} Entity;
Entity player;
unsigned int click=0;
void prepareScene(void)
{
#if 0
if(click == 1)
{
SDL_SetRenderDrawColor(app.renderer, 255, 128, 0, 255);
}
else
{
SDL_SetRenderDrawColor(app.renderer, 96, 128, 255, 255);
}
SDL_RenderClear(app.renderer);
#endif // 0
if(click == 1)
{
SDL_SetRenderDrawColor(app.renderer, 255, 128, 0, 255);
}
else
{
SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255);
}
SDL_Rect rectangle;
rectangle.x = 318;
rectangle.y = 378;
rectangle.w = 12;
rectangle.h = 6;
SDL_RenderFillRect(app.renderer, &rectangle);
}
void presentScene(void)
{
SDL_RenderPresent(app.renderer);
}
void initSDL(void)
{
int rendererFlags, windowFlags;
rendererFlags = SDL_RENDERER_ACCELERATED;
windowFlags = 0;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
app.window = SDL_CreateWindow("Apple's STM32 EK-board", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, windowFlags);
if (!app.window)
{
printf("Failed to open %d x %d window: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, SDL_GetError());
exit(1);
}
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
app.renderer = SDL_CreateRenderer(app.window, -1, rendererFlags);
if (!app.renderer)
{
printf("Failed to create renderer: %s\n", SDL_GetError());
exit(1);
}
IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
}
void cleanup(void)
{
SDL_DestroyRenderer(app.renderer);
SDL_DestroyWindow(app.window);
SDL_Quit();
}
void doInput(void)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
exit(0);
break;
case SDL_MOUSEBUTTONUP:
click = !click;
break;
default:
break;
}
}
}
int main(int argc, char *argv[])
{
memset(&app, 0, sizeof(App));
memset(&player, 0, sizeof(Entity));
initSDL();
SDL_Surface* board_bitmap = IMG_Load("pic/AppleSTM32.png");
if (board_bitmap == NULL) {
printf("Cannot load image file '%s' (%s).\n",
"pic/player.png",
IMG_GetError());
exit(1);
}
SDL_Surface* board_bitmap_rgb = SDL_ConvertSurfaceFormat(board_bitmap,SDL_PIXELFORMAT_RGB888, 0);
if (board_bitmap_rgb == 0) {
printf("Could not create surface: %s\n", SDL_GetError());
exit(1);
}
player.texture = SDL_CreateTextureFromSurface(app.renderer,board_bitmap_rgb);
if (player.texture == NULL) {
printf("Could not create texture: %s\n", SDL_GetError());
exit(1);
}
SDL_RenderClear(app.renderer);
SDL_RenderCopy(app.renderer, player.texture, NULL, NULL);
SDL_RenderPresent(app.renderer);
SDL_FreeSurface(board_bitmap);
atexit(cleanup);
while (1)
{
prepareScene();
doInput();
presentScene();
SDL_Delay(16);
}
return 0;
}
三,修改qemu中的开发板图片
boards-discovery.c中修改LED的rect,修改要打开的图片
//修改1,LED0位置
static GPIOLEDInfo stm32f429i_discovery_leds_info[] = {
{
.name = "led:green",
.active_low = false,
.colour_name = "green",
.x = 486,//519,
.y = 574,//109,
.w = 12,//10,
.h = 8,//8,
.gpio_path = DEVICE_PATH_STM32_GPIO_G,
.irq_name = STM32_IRQ_GPIO_ODR_OUT,
.gpio_bit = 13,
//修改2,背景开发板图片
BoardGraphicContext *board_graphic_context =cortexm_board_init_graphic_image(board, "AppleSTM32.png");
//cortexm_board_init_graphic_image(board, "STM32F429I-Discovery.jpg");
//修改3,窗口台头名称
mc->desc = "Apple Cai's STM32F429ZG board";//"ST Discovery kit for STM32F429/439 lines";
qemu运行我的stm32开发板效果,右下角D1处为LED灯。
四,qemu添加自定义虚拟开发板
刚刚在第三个步骤中,只是在原来的开发板基础上修改了图片。至于开发板的IO口等还是原来的。所以第四步是要在qemu中添加自定义开发板的仿真代码,而不破坏原来的开发板仿真代码。
关于如何添加开发板,要看我最早的一篇qemu源码分析,主要是调试了vl.c了解其框架及传参的作用,大家可以参考Qemu2.8虚拟机源码分析—Apple的学习笔记和qemu虚化原理入门--Apple的学习笔记,在qemu中添加一个开发板还是比较简单的。参考其它hw中的board.c文件依样画葫芦即可。我在stm32_machines_init中注册了type_register_static(&appleSTM32F429ZG_machine)
设置了board名字为AppleSTM32
。添加代码如下:
/* ----- AppleCai's STM32F429ZG board ----- */
static GPIOLEDInfo appleSTM32_leds_info[] = {
{
.name = "led:green",
.active_low = false,
.colour_name = "green",
.x = 486,
.y = 574,
.w = 12,
.h = 8,
.gpio_path = DEVICE_PATH_STM32_GPIO_F,
.irq_name = STM32_IRQ_GPIO_ODR_OUT,
.gpio_bit = 9,
/**/
},
{
.name = "led:red",
.active_low = false,
.colour_name = "red",
.x = 486,
.y = 584,
.w = 10,
.h = 8,
.gpio_path = DEVICE_PATH_STM32_GPIO_F,
.irq_name = STM32_IRQ_GPIO_ODR_OUT,
.gpio_bit = 10,
/**/
},
{ },
/**/
};
static void appleSTM32F4_board_init_callback(MachineState *machine)
{
CortexMBoardState *board = CORTEXM_BOARD_STATE(machine);
cortexm_board_greeting(board);
BoardGraphicContext *board_graphic_context =cortexm_board_init_graphic_image(board, "AppleSTM32.png");
{
// Create the MCU
Object *mcu = cm_object_new_mcu(machine, TYPE_STM32F429ZI);
// Set the board specific oscillator frequencies.
cm_object_property_set_int(mcu, 8000000, "hse-freq-hz"); // 8.0 MHz
cm_object_property_set_int(mcu, 32768, "lse-freq-hz"); // 32 kHz
cm_object_realize(mcu);
}
Object *peripheral = cm_container_get_peripheral();
// Create board LEDs.
gpio_led_create_from_info(peripheral, appleSTM32_leds_info,
board_graphic_context);
}
static void appleSTM32_discovery_init_callback(ObjectClass *oc,void *data);
static const TypeInfo appleSTM32F429ZG_machine = {
.name = BOARD_TYPE_NAME("AppleSTM32"),
.parent = TYPE_CORTEXM_BOARD,
.class_init = appleSTM32_discovery_init_callback
};
static void appleSTM32_discovery_init_callback(ObjectClass *oc,void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Apple Cai's STM32F429ZG board";
mc->init = appleSTM32F4_board_init_callback;
}
编译通过后,查看Apple cai'sboard已经添加成功
接着修改了LED工程的引脚为PF9和PF10。原来的是PG14和PG14,直接运行LED灯是不会亮的。LED工程make通过后,结合qemu进行仿真。记得传入参数
--board AppleSTM32
这样才可以调用我添加的函数。输入仿真命令qemu-system-gnuarmeclipse --verbose --verbose --board AppleSTM32 --mcu STM32F429ZI -d unimp,guest_errors --image led.elf
led工程中我设置了D1和D2两个LED灯轮流闪烁。效果如下,自定义最小开发板完工。
五,总结
通过化繁为简的方法,进行分步学习,逐渐熟悉qemu源码框架及其子系统,并且掌握qemu自定义开发板和外设的方法。真的好好玩啊~