Mbed在自己的stm32系列平台移植适配

原文链接:Mbed在自己的stm32系列平台移植适配

适配平台:
cpu:STM32F103RCT6
外设:

peripheralpindisciption
LED1PC_0
LED2PC_6
UART5_TXPC_12no remap
UART5_RXPD_2no remap

引用资源:
mbed在线编译器
Mbed源码仓库
Stm32f1官方hal库

三、适配开发板

1适配芯片

首先将芯片修改为stm32f103RC

然后从st官网的hal库中拷贝其他芯片的头文件和启动文件过来,
同时mbed工程中的sct文件只有stm32f103xb.sct,我们复制一分然后重命名为stm32f103xe.sct。
修改stm32f1xx.h文件,注释掉#define STM32F103xB,取消注释#define STM32F103xE。

#if !defined (STM32F100xB) && !defined (STM32F100xE) && !defined (STM32F101x6) && \
    !defined (STM32F101xB) && !defined (STM32F101xE) && !defined (STM32F101xG) && !defined    (STM32F102x6) && !defined (STM32F102xB) && !defined (STM32F103x6) && \
    !defined (STM32F103xB) && !defined (STM32F103xE) && !defined (STM32F103xG) && !defined (STM32F105xC) && !defined (STM32F107xC)
  /* #define STM32F100xB */   /*!< STM32F100C4, STM32F100R4, STM32F100C6, STM32F100R6, STM32F100C8, STM32F100R8, STM32F100V8, STM32F100CB, STM32F100RB and STM32F100VB */
  /* #define STM32F100xE */   /*!< STM32F100RC, STM32F100VC, STM32F100ZC, STM32F100RD, STM32F100VD, STM32F100ZD, STM32F100RE, STM32F100VE and STM32F100ZE */
  /* #define STM32F101x6 */   /*!< STM32F101C4, STM32F101R4, STM32F101T4, STM32F101C6, STM32F101R6 and STM32F101T6 Devices */
  /* #define STM32F101xB */   /*!< STM32F101C8, STM32F101R8, STM32F101T8, STM32F101V8, STM32F101CB, STM32F101RB, STM32F101TB and STM32F101VB */
  /* #define STM32F101xE */   /*!< STM32F101RC, STM32F101VC, STM32F101ZC, STM32F101RD, STM32F101VD, STM32F101ZD, STM32F101RE, STM32F101VE and STM32F101ZE */ 
  /* #define STM32F101xG */   /*!< STM32F101RF, STM32F101VF, STM32F101ZF, STM32F101RG, STM32F101VG and STM32F101ZG */
  /* #define STM32F102x6 */   /*!< STM32F102C4, STM32F102R4, STM32F102C6 and STM32F102R6 */
  /* #define STM32F102xB */   /*!< STM32F102C8, STM32F102R8, STM32F102CB and STM32F102RB */
  /* #define STM32F103x6 */   /*!< STM32F103C4, STM32F103R4, STM32F103T4, STM32F103C6, STM32F103R6 and STM32F103T6 */
/* #define STM32F103xB */   /*!< STM32F103C8, STM32F103R8, STM32F103T8, STM32F103V8, STM32F103CB, STM32F103RB, STM32F103TB and STM32F103VB */
   #define STM32F103xE    /*!< STM32F103RC, STM32F103VC, STM32F103ZC, STM32F103RD, STM32F103VD, STM32F103ZD, STM32F103RE, STM32F103VE and STM32F103ZE */
  /* #define STM32F103xG */   /*!< STM32F103RF, STM32F103VF, STM32F103ZF, STM32F103RG, STM32F103VG and STM32F103ZG */
  /* #define STM32F105xC */   /*!< STM32F105R8, STM32F105V8, STM32F105RB, STM32F105VB, STM32F105RC and STM32F105VC */
  /* #define STM32F107xC*/    /*!< STM32F107RB, STM32F107VB, STM32F107RC and STM32F107VC */  
#endif

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

好了,芯片的匹配工作完成,注意由于原本工程中的启动文件是用的startup_stm32f103xb.S,需要修改成startup_stm32f103xe.S

同时sct文件路径也要指定为stm32f103xe.sct

2适配晶振频率(如果不需要修改的可以跳过该步骤)

因为默认的开发板使用的是8MHz晶振,而我用的是12MHz,所以需要做晶振频率的修改。
修改文件system_stm32f1xx.c(注意mbed中的该文件内部集成了时钟初始化,而官方自带的hal中该文件没有进行时钟的初始化)
我们先来对比一下system_stm32f1xx.c文件的SystemInit函数
这是mbed的自带的

    void SystemInit (void)
    {
      /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
      /* Set HSION bit */
      RCC->CR |= (uint32_t)0x00000001;

      /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    #if !defined(STM32F105xC) && !defined(STM32F107xC)
      RCC->CFGR &= (uint32_t)0xF8FF0000;
    #else
      RCC->CFGR &= (uint32_t)0xF0FF0000;
    #endif /* STM32F105xC */   

      /* Reset HSEON, CSSON and PLLON bits */
      RCC->CR &= (uint32_t)0xFEF6FFFF;

      /* Reset HSEBYP bit */
      RCC->CR &= (uint32_t)0xFFFBFFFF;

      /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
      RCC->CFGR &= (uint32_t)0xFF80FFFF;

    #if defined(STM32F105xC) || defined(STM32F107xC)
      /* Reset PLL2ON and PLL3ON bits */
      RCC->CR &= (uint32_t)0xEBFFFFFF;

      /* Disable all interrupts and clear pending bits  */
      RCC->CIR = 0x00FF0000;

      /* Reset CFGR2 register */
      RCC->CFGR2 = 0x00000000;
    #elif defined(STM32F100xB) || defined(STM32F100xE)
      /* Disable all interrupts and clear pending bits  */
      RCC->CIR = 0x009F0000;

      /* Reset CFGR2 register */
      RCC->CFGR2 = 0x00000000;      
    #else
      /* Disable all interrupts and clear pending bits  */
      RCC->CIR = 0x009F0000;
    #endif /* STM32F105xC */

    #if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
      #ifdef DATA_IN_ExtSRAM
        SystemInit_ExtMemCtl(); 
      #endif /* DATA_IN_ExtSRAM */
    #endif 

    #ifdef VECT_TAB_SRAM
      SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    #else
      SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
    #endif

      /* Configure the Cube driver */
      SystemCoreClock = 8000000; // At this stage the HSI is used as system clock
      HAL_Init();

      /* Configure the System clock source, PLL Multiplier and Divider factors,
         AHB/APBx prescalers and Flash settings */
      SetSysClock();

      /* Reset the timer to avoid issues after the RAM initialization */
      TIM_MST_RESET_ON;
      TIM_MST_RESET_OFF;
    }

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

我们可以从中可以看到调用了SetSysClock()函数,这个函数就是进行时钟设置的。
相反的如果我们从st自带的hal库中打开一个Example,可以看到st的hal库中的时钟设置部分都是放在main函数的开头的。
其实道理是一样的,因为systemInit执行完了后接着就会执行main函数了,所以时钟初始化放在systeminit的末位和放在main的开头是等效的。

好了,开始适配晶振。由于我使用的是12MHz的晶振,通过12MHz*6=72MHz来产生72MHz的主频。因为时钟初始化实是在SetSysClock中。
跟踪
SetSysClock–>SetSysClock_PLL_HSE。我们可以知道需要修改SetSysClock_PLL_HSE函数,

    RCC_OscInitStruct.HSEPredivValue      = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.PLL.PLLState        = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource       = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL          = RCC_PLL_MUL9; // 72 MHz (8 MHz * 9)

 
 
 
 
  • 1
  • 2
  • 3
  • 4

将RCC_PLL_MUL9改为RCC_PLL_MUL6,因为我们将使用12MHz*6=72MHz的倍频方式

然后在整个工程中全局搜索HSE_VALUE定义
可以得到在stm32f1xx_hal_conf.h和system_stm32f1xx.c中分别有定义,比如我用的12MHz,我就修改成12000000
理论上只需要修改stm32f1xx_hal_conf.h中的即可,但是为了安全还是全部改了吧。

3适配分散文件sct

mbed对堆栈的定义做了自己的定义这个跟st自带的堆栈分配并不一样,所以需要做修改,这样就直接导致了sct的空间分布需要修改。打开mbed自带的stm32f103xb.sct文件。

    LR_IROM1 0x08000000 0x20000  {    ; load region size_region (128K)

      ER_IROM1 0x08000000 0x20000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
       .ANY (+RO)
      }

      ; 59 vectors (16 core + 43 peripheral) * 4 bytes = 236 bytes to reserve (0xEC)
      RW_IRAM1 (0x20000000+0xEC) (0x5000-0xEC)  {  ; RW data
       .ANY (+RW +ZI)
      }

    }

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们可以从中看到在ram的分配上预留了大小为0xEC的空间,而这个空间的大小是根据中断向量个数来决定的,可以猜测这个预留空间可能会将向量表重载到这个地方。我们将这个文件适配成stm32f103RC使用的。
因为stm32f103RC的flash=0x40000,ram=0xC000,中断个数可以查看启动文件。

__Vectors       DCD     __initial_sp               ; Top of Stack
            DCD     Reset_Handler              ; Reset Handler
            DCD     NMI_Handler                ; NMI Handler
            DCD     HardFault_Handler          ; Hard Fault Handler
            DCD     MemManage_Handler          ; MPU Fault Handler
            DCD     BusFault_Handler           ; Bus Fault Handler
            DCD     UsageFault_Handler         ; Usage Fault Handler
            DCD     0                          ; Reserved
            DCD     0                          ; Reserved
            DCD     0                          ; Reserved
            DCD     0                          ; Reserved
            DCD     SVC_Handler                ; SVCall Handler
            DCD     DebugMon_Handler           ; Debug Monitor Handler
            DCD     0                          ; Reserved
            DCD     PendSV_Handler             ; PendSV Handler
            DCD     SysTick_Handler            ; SysTick Handler

            ; External Interrupts
            DCD     WWDG_IRQHandler            ; Window Watchdog
            DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
            DCD     TAMPER_IRQHandler          ; Tamper
            DCD     RTC_IRQHandler             ; RTC
            DCD     FLASH_IRQHandler           ; Flash
            DCD     RCC_IRQHandler             ; RCC
            DCD     EXTI0_IRQHandler           ; EXTI Line 0
            DCD     EXTI1_IRQHandler           ; EXTI Line 1
            DCD     EXTI2_IRQHandler           ; EXTI Line 2
            DCD     EXTI3_IRQHandler           ; EXTI Line 3
            DCD     EXTI4_IRQHandler           ; EXTI Line 4
            DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
            DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
            DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
            DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
            DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
            DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
            DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
            DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
            DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
            DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
            DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
            DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
            DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
            DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
            DCD     TIM1_UP_IRQHandler         ; TIM1 Update
            DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
            DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
            DCD     TIM2_IRQHandler            ; TIM2
            DCD     TIM3_IRQHandler            ; TIM3
            DCD     TIM4_IRQHandler            ; TIM4
            DCD     I2C1_EV_IRQHandler         ; I2C1 Event
            DCD     I2C1_ER_IRQHandler         ; I2C1 Error
            DCD     I2C2_EV_IRQHandler         ; I2C2 Event
            DCD     I2C2_ER_IRQHandler         ; I2C2 Error
            DCD     SPI1_IRQHandler            ; SPI1
            DCD     SPI2_IRQHandler            ; SPI2
            DCD     USART1_IRQHandler          ; USART1
            DCD     USART2_IRQHandler          ; USART2
            DCD     USART3_IRQHandler          ; USART3
            DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
            DCD     RTC_Alarm_IRQHandler        ; RTC Alarm through EXTI Line
            DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
            DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
            DCD     TIM8_UP_IRQHandler         ; TIM8 Update
            DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
            DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
            DCD     ADC3_IRQHandler            ; ADC3
            DCD     FSMC_IRQHandler            ; FSMC
            DCD     SDIO_IRQHandler            ; SDIO
            DCD     TIM5_IRQHandler            ; TIM5
            DCD     SPI3_IRQHandler            ; SPI3
            DCD     UART4_IRQHandler           ; UART4
            DCD     UART5_IRQHandler           ; UART5
            DCD     TIM6_IRQHandler            ; TIM6
            DCD     TIM7_IRQHandler            ; TIM7
            DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
            DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
            DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
            DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

数了一下总共是16+60=76个,所以sct可以这样写:

LR_IROM1 0x08000000 0x40000  {    ; load region size_region (128K)

  ER_IROM1 0x08000000 0x40000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }

  ; 76 vectors (16 core + 60 peripheral) * 4 bytes = 304 bytes to reserve (0x130)
  RW_IRAM1 (0x20000000+0x130) (0xC000-0x130)  {  ; RW data
   .ANY (+RW +ZI)
  }

}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4适配启动文件

因为需要重新定义堆栈,所以堆栈地址需要修改,同时默认的开发板使用的是stm32f103RB,而我用的是stm32f103RC,支持的中断和外设比RB要多,所以需要加上去,此处可以使用st官方的hal库中的RC启动文件,然后修改堆栈地址。
删除掉自带的堆栈设置,添加mbed需要的堆栈地址

然后删除掉自带文件的堆栈初始化操作

5适配pinname,peripheralname和peripheralpin

关于这三个东西,如果我们仔细研究一下他们的源码后,我们就会发现一个很有意思的东西
PeripheralPins
PeripheralNames
PinNames
这三个文件可以剥离出三个东西,peripheral、pin和name
Name好理解,主体是pin和peripheral
Pin的注册名称就是pinnames

LED1        = PC_0,
LED2        = PC_6,
LED3        = PC_0,
LED4        = PC_6,
USER_BUTTON = PC_13,
SERIAL_TX   = PA_9,
SERIAL_RX   = PA_10,
USBTX       = PA_2,
USBRX       = PA_3,

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

peripheral的注册名就是peripheralnames

typedef enum {
    UART_1 = (int)USART1_BASE,
    UART_2 = (int)USART2_BASE,
    UART_3 = (int)USART3_BASE,
    UART_4 = (int)UART4_BASE,
    UART_5 = (int)UART5_BASE,
} UARTName;

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

将peripheral和pin组合在一起同时添加一些特征功能就是peripheralpin

const PinMap PinMap_UART_TX[] = {
    {PA_2,  UART_2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 0)},
    {PA_9,  UART_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 0)},
    {PB_6,  UART_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 3)}, // GPIO_Remap_USART1
    {PB_10, UART_3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 0)},
    {PC_10, UART_3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 5)}, // GPIO_PartialRemap_USART3
    {PC_12, UART_5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 0)},
    {NC,    NC,     0}
};

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

peripheralpin就是跟上层打交道的。打交道的api集中在pinmap中

现在开始适配这三项
比如我的外设是这样的
LED1——————-PC_0
LED2——————-PC_6
UART5_TX————PC_12
UART5_RX————PD_2
添加pinname

LED1        = PC_0,
LED2        = PC_6,
.....
SERIAL_TX   = PA_9,
SERIAL_RX   = PA_10,

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

添加peripheralname

UART_4 = (int)UART4_BASE,
UART_5 = (int)UART5_BASE,

 
 
 
 
  • 1
  • 2

添加peripheralpin
在PinMap_UART_TX中添加

{PC_12, UART_5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, 0)},

 
 
 
 
  • 1

该句一定要放在结束符

{NC,    NC,     0}

 
 
 
 
  • 1

之前
同理在PinMap_UART_RX中添加

{PD_2,  UART_5, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, 0)},

 
 
 
 
  • 1

关于STM_PIN_DATA(),这其实是一个宏定义,最后一个参数是一个复用的索引表,这个索引表在pinmap文件中有所体现。

switch (afnum) {
        case 1: // Remap SPI1
            __HAL_AFIO_REMAP_SPI1_ENABLE();
            break;
        case 2: // Remap I2C1
            __HAL_AFIO_REMAP_I2C1_ENABLE();
            break;
        case 3: // Remap USART1
            __HAL_AFIO_REMAP_USART1_ENABLE();
            break;
        case 4: // Remap USART2
            __HAL_AFIO_REMAP_USART2_ENABLE();
            break;
        case 5: // Partial Remap USART3
            __HAL_AFIO_REMAP_USART3_PARTIAL();
            break;
        case 6: // Partial Remap TIM1
            __HAL_AFIO_REMAP_TIM1_PARTIAL();
            break;
        case 7: // Partial Remap TIM3
            __HAL_AFIO_REMAP_TIM3_PARTIAL();
            break;
        case 8: // Full Remap TIM2
            __HAL_AFIO_REMAP_TIM2_ENABLE();
            break;
        case 9: // Full Remap TIM3
            __HAL_AFIO_REMAP_TIM3_ENABLE();
            break;
        case 10: // CAN_RX mapped to PB8, CAN_TX mapped to PB9
            __HAL_AFIO_REMAP_CAN1_2();
            break;
        default:
            break;
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

具体对应表格如下:

numdiscriptionfunction
1Remap SPI1__HAL_AFIO_REMAP_SPI1_ENABLE
2Remap I2C1__HAL_AFIO_REMAP_I2C1_ENABLE
3Remap USART1__HAL_AFIO_REMAP_USART1_ENABLE
4Remap USART2__HAL_AFIO_REMAP_USART2_ENABLE
5Partial Remap USART3__HAL_AFIO_REMAP_USART3_PARTIAL
6Partial Remap TIM1__HAL_AFIO_REMAP_TIM1_PARTIAL
7Partial Remap TIM3__HAL_AFIO_REMAP_TIM3_PARTIAL
8Full Remap TIM2__HAL_AFIO_REMAP_TIM2_ENABLE
9Full Remap TIM3__HAL_AFIO_REMAP_TIM3_ENABLE
10CAN_RX mapped to PB8/CAN_TX mapped to PB9__HAL_AFIO_REMAP_CAN1_2

6适配串口初始化

a修改标准输入输出端口:

修改PeripheralNames

#define STDIO_UART_TX  PC_12
#define STDIO_UART_RX  PD_2
#define STDIO_UART     UART_5

 
 
 
 
  • 1
  • 2
  • 3

这是标准输入输出终端串口配置

b修改波特率

Mbedconfig.h

#define MBED_CONF_PLATFORM_STDIO_BAUD_RATE          9600
#define MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE  9600

 
 
 
 
  • 1
  • 2

第一个是标准输入输出串口的默认波特率设置
第二个是普通串口的默认波特率设置

c添加初始化

串口的初始化程序在serial_api.c文件中
void serial_init(serial_t *obj, PinName tx, PinName rx)
由于自带的只有USART_1、USART_2和USART_3,我们现在要适配UART_4和UART_5,那么凡是有USART_1、USART_2和USART_3的地方我们都要参照这适配出UART_4和UART_5,全局搜索USART_3,找出需要增加UART_4和UART_5的地方,

serial_init函数中:

if (obj_s->uart == UART_1) {
    __HAL_RCC_USART1_FORCE_RESET();
    __HAL_RCC_USART1_RELEASE_RESET();
    __HAL_RCC_USART1_CLK_ENABLE();
    obj_s->index = 0;
}
if (obj_s->uart == UART_2) {
    __HAL_RCC_USART2_FORCE_RESET();
    __HAL_RCC_USART2_RELEASE_RESET();
    __HAL_RCC_USART2_CLK_ENABLE();
    obj_s->index = 1;
}
if (obj_s->uart == UART_3) {
    __HAL_RCC_USART3_FORCE_RESET();
    __HAL_RCC_USART3_RELEASE_RESET();
    __HAL_RCC_USART3_CLK_ENABLE();
    obj_s->index = 2;
}
在后面添加

if (obj_s->uart == UART_4) {
    __HAL_RCC_UART4_FORCE_RESET();
    __HAL_RCC_UART4_RELEASE_RESET();
    __HAL_RCC_UART4_CLK_ENABLE();
    obj_s->index = 3;
}
    if (obj_s->uart == UART_5) {
    __HAL_RCC_UART5_FORCE_RESET();
    __HAL_RCC_UART5_RELEASE_RESET();
    __HAL_RCC_UART5_CLK_ENABLE();
    obj_s->index = 4;
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

同时我么注意到obj_s->index也在增加,查找一下发现obj_s->index跟串口个数有关所以UART_NUM修改成 5

#define UART_NUM (5)

static uint32_t serial_irq_ids[UART_NUM] = {0};
static UART_HandleTypeDef uart_handlers[UART_NUM];

 
 
 
 
  • 1
  • 2
  • 3
  • 4

同时还有两处的USART_3要适配成UART_5
serial_free函数中:

if (obj_s->uart == UART_1) {
    __USART1_FORCE_RESET();
    __USART1_RELEASE_RESET();
    __USART1_CLK_DISABLE();
}
if (obj_s->uart == UART_2) {
    __USART2_FORCE_RESET();
    __USART2_RELEASE_RESET();
    __USART2_CLK_DISABLE();
}
if (obj_s->uart == UART_3) {
    __USART3_FORCE_RESET();
    __USART3_RELEASE_RESET();
    __USART3_CLK_DISABLE();
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在后面添加

if (obj_s->uart == UART_4) {
    __UART4_FORCE_RESET();
    __UART4_RELEASE_RESET();
    __UART4_CLK_DISABLE();
}
    if (obj_s->uart == UART_5) {
    __UART5_FORCE_RESET();
    __UART5_RELEASE_RESET();
    __UART5_CLK_DISABLE();
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在serial_irq_set函数中

if (obj_s->uart == UART_1) {
    irq_n = USART1_IRQn;
    vector = (uint32_t)&uart1_irq;
}

if (obj_s->uart == UART_2) {
    irq_n = USART2_IRQn;
    vector = (uint32_t)&uart2_irq;
}

if (obj_s->uart == UART_3) {
    irq_n = USART3_IRQn;
    vector = (uint32_t)&uart3_irq;
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在后面添加

if (obj_s->uart == UART_4) {
    irq_n = UART4_IRQn;
    vector = (uint32_t)&uart4_irq;
}

if (obj_s->uart == UART_5) {
    irq_n = UART5_IRQn;
    vector = (uint32_t)&uart5_irq;
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

然后发现uart4_irq和uart5_irq没有定义,我们搜索一下uart3_irq,并参照着uart3_irq定义uart4_irq和uart5_irq

static void uart4_irq(void)
{
    uart_irq(3);
}

static void uart5_irq(void)
{
    uart_irq(4);
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

同时修改uart_irq,添加参数3和参数4的部分

if (__HAL_UART_GET_FLAG(huart, UART_FLAG_TC) != RESET) {
    if (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC) != RESET) {
        irq_handler(serial_irq_ids[id], TxIrq);
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);
    }
}
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE) != RESET) {
    if (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE) != RESET) {
        irq_handler(serial_irq_ids[id], RxIrq);
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_RXNE);
    }
}
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) {
    if (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET) {
        volatile uint32_t tmpval = huart->Instance->DR; // Clear ORE flag
    }
}

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

发现没什么要修改的。

修改完这些之后,编译应该就没有问题了,下载到开发板中也能工作正常了。

7关于编译选项的研究

为什么要研究编译选项?细心的同学可能会注意到我前面创建工程的一个细节,我的工程并不是自己使用MDK手动创建的,而是通过在线的编译器导出的。然后我有将工程中的所有文件全部更换成了mbed源码库中的文件和st hal官方库中的文件。既然文件我全部都替换了,那么我为什么不自己用MDK手动建立一个新工程呢?原因就在于编译选项上。手动新建的工程使用了一些默认的编译选项,而我们导出的mbed工程使用了一些自定义的编译选项,这些选项太多了,设置起来比较麻烦,所以我为了方便,就直接引用了导入的工程。
那么现在你是否能够想到另外的一些想法:我用MDK手动新建一个工程,然后参照这mbed导出工程的编译选项来调整这个工程,那么这样的工程是否可用呢?答案是完全没问题。所以,现在我们得到了两种创建工程的方法。
第一种:使用mbed在线编译器导出工程,然后替换所有的mbed文件。
第二种:使用MDK手动创建工程,然后添加mbed库文件,然后照着之前导出的mbed编译选项设置。
所以,现在我们就需要来研究一下mbed的编译选项,因为这不仅关系到工程创建,同样关系到工程移植。

为了更方便研究,我们直接将其复制到文本编辑器中:

-DDEVICE_RTC=1 -DDEVICE_SLEEP=1 -DTOOLCHAIN_object -DTOOLCHAIN_ARM_STD -D__ASSERT_MSG -DTARGET_STM32F1 --no_rtti -DTARGET_STM32F103RB -DMBED_BUILD_TIMESTAMP=1484039781.98 -Otime -DDEVICE_PORTINOUT=1 -D__CORTEX_M3 -DTARGET_FF_ARDUINO -c -O3 -DDEVICE_CAN=1 -DDEVICE_PORTOUT=1 -DDEVICE_STDIO_MESSAGES=1 -DTARGET_RELEASE --split_sections -DARM_MATH_CM3 -DTARGET_LIKE_CORTEX_M3 -DDEVICE_ANALOGIN=1 -DTARGET_NUCLEO_F103RB -DDEVICE_PORTIN=1 -DTARGET_CORTEX_M --cpu=Cortex-M3 -DTARGET_FF_MORPHO -DDEVICE_I2C=1 --preinclude=mbed_config.h -DTARGET_STM -DTOOLCHAIN_ARM -DDEVICE_INTERRUPTIN=1 --no_depend_system_headers -DTARGET_UVISOR_UNSUPPORTED --md -DDEVICE_PWMOUT=1 -DDEVICE_SERIAL_ASYNCH=1 --gnu --apcs=interwork -DDEVICE_SPI=1 -D__MBED__=1 -DDEVICE_SPISLAVE=1 -DDEVICE_SERIAL=1 -DTARGET_M3 -DDEVICE_I2CSLAVE=1 -D__CMSIS_RTOS -D__MBED_CMSIS_RTOS_CM -DTARGET_LIKE_MBED

 
 
 
 
  • 1

-D开头的都是预编译宏定义,等效于define中的定义

这是所有的-D选项,我们可以将这些选项直接设置在Define选项栏中

-DDEVICE_RTC=1 
-DDEVICE_SLEEP=1 
-DTOOLCHAIN_object (x)
-DTOOLCHAIN_ARM_STD 
-D__ASSERT_MSG (x)
-DTARGET_STM32F1 
-DTARGET_STM32F103RB 
-DDEVICE_PORTINOUT=1 
-D__CORTEX_M3 
-DTARGET_FF_ARDUINO 
-DDEVICE_CAN=1 
-DDEVICE_PORTOUT=1 
-DDEVICE_STDIO_MESSAGES=1 
-DTARGET_RELEASE 
-DARM_MATH_CM3 
-DTARGET_LIKE_CORTEX_M3 
-DDEVICE_ANALOGIN=1 
-DTARGET_NUCLEO_F103RB 
-DDEVICE_PORTIN=1 
-DTARGET_CORTEX_M 
-DTARGET_FF_MORPHO 
-DDEVICE_I2C=1 
-DTARGET_STM -DTOOLCHAIN_ARM 
-DDEVICE_INTERRUPTIN=1 
-DTARGET_UVISOR_UNSUPPORTED 
-DDEVICE_PWMOUT=1 
-DDEVICE_SERIAL_ASYNCH=1 
-DDEVICE_SPI=1 
-D__MBED__=1 
-DDEVICE_SPISLAVE=1 
-DMBED_BUILD_TIMESTAMP=1484275342.19 
-DDEVICE_SERIAL=1 
-DTARGET_M3 
-DDEVICE_I2CSLAVE=1 
-D__CMSIS_RTOS 
-D__MBED_CMSIS_RTOS_CM 
-DTARGET_LIKE_MBED

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

这是11个非-D选项

--no_rtti 
-Otime (Optimize for Time)
-c 
-O3 (Optimization)
--split_sections 
--cpu=Cortex-M3 
--preinclude=mbed_config.h 
--no_depend_system_headers 
--md 
--gnu 
--apcs=interwork 

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这几个选项我们来看看什么意思,编译选项的含义我们需要查阅arm的官方编译手册

-no_rtti

Controls support for the RTTI features dynamic_cast and typeid in C++.
Usage
Use --no_rtti to disable source-level RTTI features such as dynamic_cast.
 Note 
You are permitted to use dynamic_cast without --rtti in cases where RTTI is not required, such as
dynamic cast to an unambiguous base, and dynamic cast to (void *). If you try to use dynamic_cast
without --rtti in cases where RTTI is required, the compiler generates an error.

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这个选项是针对C++的语法支持的,需要详细了解自己百度谷歌。
-Otime

Performs optimizations to reduce execution time at the expense of a possible increase in image size.
Use this option if execution time is more critical than code size. If required, you can compile the time-
critical parts of your code with -Otime, and the rest with -Ospace.
Default
If you do not specify -Otime, the compiler assumes -Ospace.

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

这个选项相当于MDK自带的设置选项Optimize for Time

-c
这个好理解,就是只编译,不链接,默认选项就是带有这个选项的。

-O3
优化等级,相当于MDK自带的Optimization选项

–split_sections
太专业的咋也说不清,看手册
–cpu=Cortex-M3
这个选项好懂,只要芯片选择了,这个选项会自动添加上的

–preinclude=mbed_config.h
–preinclude选项用来自定头文件的路径,等效于MDK自带的include设置项

-no_depend_system_headers
–md
–gnu
–apcs=interwork
这四个直接查阅手册吧。
介绍了上面的这些选项可能并不太懂什么意思,没关系,照着写就行了。

下面我们看看-D的一些选项,这些选项我们可以到源码中通过全局搜索看看在什么地方使用了这些选项,然后分析这些选项有什么用。
我们搜索一下

注意此处look in选项和include sub-folders选项,因为我们mbed工程中的有些文件并没有包含到工程中,比如rtos文件夹下面的文件,还有一些头文件,所以直接指明搜索路径搜索的更全一些

TARGET_STM32F103RB这个选项关系到代码移植,我们要移植成TARGET_STM32F103RC
通过搜索我们可以找到引用这个宏定义的地方

#elif defined(TARGET_STM32F100RB)

#ifndef INITIAL_SP
#define INITIAL_SP              (0x20002000UL)
#endif
#ifndef OS_TASKCNT
#define OS_TASKCNT              6
#endif
#ifndef OS_MAINSTKSIZE
#define OS_MAINSTKSIZE          128
#endif
#ifndef OS_CLOCK
#define OS_CLOCK                24000000
#endif

#elif defined(TARGET_STM32F103RB)

#ifndef INITIAL_SP
#define INITIAL_SP              (0x20005000UL)
#endif
#ifndef OS_TASKCNT
#define OS_TASKCNT              6
#endif
#ifndef OS_MAINSTKSIZE
#define OS_MAINSTKSIZE          128
#endif
#ifndef OS_CLOCK
#define OS_CLOCK                72000000
#endif

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在后面添加

#elif defined(TARGET_STM32F103RC)

#ifndef INITIAL_SP
#define INITIAL_SP              (0x2000C000UL)
#endif
#ifndef OS_TASKCNT
#define OS_TASKCNT              6
#endif
#ifndef OS_MAINSTKSIZE
#define OS_MAINSTKSIZE          128
#endif
#ifndef OS_CLOCK
#define OS_CLOCK                72000000
#endif

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

好了至此移植彻底完成了。

工程模板

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值