qemu上跑stm32 模拟stm32开发板


qemu早就可以跑stm32程序了。很简单:

windows bat:

cd C:\Program Files\qemu

.\qemu-system-arm.exe ^
-M netduinoplus2 ^
-nographic ^
-kernel C:\Users\kk\STM32CubeIDE\workspace_1.4.0\uart405\Debug\uart405.elf

pause

(在window上安装qemu软件,然后把这段保存成 .bat 脚本,运行。然后就能在cmd窗口下看到程序的打印)

linux上的shell脚本可做类似修改。

1. stm32的源码:

  不废话了,就是用stm32cubeIDE一键生成的代码,选STM32F405RG,会stm32的知道,没有难度。uart没有使用中断。rcc用的内部晶振,其实就是默认配置一点都没改。

改动只有:

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  char *pData = "hello qemu\n";
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_UART_Transmit(&huart1, (uint8_t*)pData, strlen(pData), 100);
	  HAL_Delay(1000);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

2. 重点说说qemu的源码:

hw/arm/netduinoplus2.c

static void netduinoplus2_init(MachineState *machine)
{
    DeviceState *dev;

    /*
     * TODO: ideally we would model the SoC RCC and let it handle
     * system_clock_scale, including its ability to define different
     * possible SYSCLK sources.
     */
    system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;

    dev = qdev_new(TYPE_STM32F405_SOC);
    qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);

    armv7m_load_kernel(ARM_CPU(first_cpu),
                       machine->kernel_filename,
                       FLASH_SIZE);
}

  netduinoplus2是一种开发板,亚马逊上有卖。它内置的就是一个STM32F405RG

在qemu里真正的芯片实现:hw/arm/stm32f405_soc.c

目前只实现了几个外设,大部分是未实现的

#define SYSCFG_ADD                     0x40013800
static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800,
                                       0x40004C00, 0x40005000, 0x40011400,
                                       0x40007800, 0x40007C00 };
/* At the moment only Timer 2 to 5 are modelled */
static const uint32_t timer_addr[] = { 0x40000000, 0x40000400,
                                       0x40000800, 0x40000C00 };
static const uint32_t adc_addr[] = { 0x40012000, 0x40012100, 0x40012200,
                                     0x40012300, 0x40012400, 0x40012500 };
static const uint32_t spi_addr[] =   { 0x40013000, 0x40003800, 0x40003C00,
                                       0x40013400, 0x40015000, 0x40015400 };
#define EXTI_ADDR                      0x40013C00

#define SYSCFG_IRQ               71
static const int usart_irq[] = { 37, 38, 39, 52, 53, 71, 82, 83 };
static const int timer_irq[] = { 28, 29, 30, 50 };
#define ADC_IRQ 18
static const int spi_irq[] =   { 35, 36, 51, 0, 0, 0 };
static const int exti_irq[] =  { 6, 7, 8, 9, 10, 23, 23, 23, 23, 23, 40,
                                 40, 40, 40, 40, 40} ;


0x40011000就是uart1基地址,这个和stm32代码、STM32F405RG是配套的。
uart1会被qemu默认映射到cmd窗口。qemu还支持映射到文件、网络端口等等,参考qemu文档


qemu支持gdb调试,会生成gdb server。命令如下
-gdb tcp::10101 ^

-S


可以用stm32cubeIDE通过TCP 端口远程调试qemu里的程序。有时间再试