RT-Thread 基於STM32F1xx HAL 庫的學習筆記(1)---加入HAL庫
移植環境:開發板 arm fly V3開發板,編譯環境 Keil MDK 5 ,win7 64平臺
【1】 將rt-thread-2.1.0\bsp目錄下的stm32f10x複製一份,然後重新命名成stm32f10x-curer。
【2】 將Libraries目錄下的檔案和資料夾更換成新的CMSIS資料夾和STM32F1xx_HAL_Driver,SConscript保留。
【3】 用Note Plus開啟stm32f10x-curer根目錄下rtconfig.py,定位到32行附近,指定ARMCC編譯器的安裝位置,修改如下:
if CROSS_TOOL == 'gcc': PLATFORM = 'gcc' EXEC_PATH = 'D:/SourceryGCC/bin' elif CROSS_TOOL == 'keil': PLATFORM = 'armcc' EXEC_PATH = 'D:/Keil_v5' elif CROSS_TOOL == 'iar': PLATFORM = 'iar' IAR_PATH = 'C:/Program Files/IAR Systems/Embedded Workbench 6.0 Evaluation' if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH')
然後儲存。
【4】在STM32F1xx_HAL_Driver目錄下新增一個SConscript,內容如下:然後儲存。如果沒有HAL庫,可以下載一個STM32F CubeMX軟體生成一個,很方便。import rtconfig Import('RTT_ROOT') from building import * # get current directory cwd = GetCurrentDir() # The set of source files associated with this SConscript file. src = Glob('Src/*.c') path = [cwd + '/Inc'] CPPDEFINES = ['USE_HAL_DRIVER'] group = DefineGroup('STM32F1xx_HAL_Driver', src, depend = [''], CPPPATH = path, CPPDEFINES = CPPDEFINES) Return('group')
【5】複製stm32f411-nucleo\drivers分支目錄下的drv_usart.c和drv_usart.h,drv_led.c和drv_led.h,然後修改之。
因為arm fly V3的LED燈埠控制引腳是PF6,所以上面程式碼也要相應改過來。int rt_led_hw_init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOF_CLK_ENABLE(); /* Configure GPIO pin: PI1 (LD1) */ GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); return 0; } INIT_BOARD_EXPORT(rt_led_hw_init);
【6】修改drv_uart.c,下面是程式碼有修改的部分,可以對照一下
在修改drv_uart.c之前先修改下\stm32f10x-curer\drivers目錄下的Conscript指令碼,修改如下:
# add the general drivers.
src = Split("""
board.c
stm32f1xx_it.c
drv_led.c
drv_usart.c
""")
然後修改drv_uart.c,結果如下:
#if defined(RT_USING_UART1)
/* UART1 device driver structure */
static struct drv_uart uart1;
struct rt_serial_device serial1;
void USART1_IRQHandler(void)
{
struct drv_uart *uart;
uart = &uart1;
/* enter interrupt */
rt_interrupt_enter();
/* UART in mode Receiver -------------------------------------------------*/
if ((__HAL_UART_GET_FLAG(&uart->UartHandle, UART_FLAG_RXNE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&uart->UartHandle, UART_IT_RXNE) != RESET))
{
rt_hw_serial_isr(&serial1, RT_SERIAL_EVENT_RX_IND);
/* Clear RXNE interrupt flag */
__HAL_UART_CLEAR_FLAG(&uart->UartHandle, UART_FLAG_RXNE);
}
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* RT_USING_UART1 */
#if defined(RT_USING_UART2)
/* UART1 device driver structure */
static struct drv_uart uart2;
struct rt_serial_device serial2;
void USART2_IRQHandler(void)
{
struct drv_uart *uart;
uart = &uart2;
/* enter interrupt */
rt_interrupt_enter();
/* UART in mode Receiver -------------------------------------------------*/
if ((__HAL_UART_GET_FLAG(&uart->UartHandle, UART_FLAG_RXNE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&uart->UartHandle, UART_IT_RXNE) != RESET))
{
rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
/* Clear RXNE interrupt flag */
__HAL_UART_CLEAR_FLAG(&uart->UartHandle, UART_FLAG_RXNE);
}
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* RT_USING_UART2 */
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* - NVIC configuration for UART interrupt request enable
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
#if defined(RT_USING_UART1)
if (huart->Instance == USART1)
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
USART1_TX_GPIO_CLK_ENABLE();
USART1_RX_GPIO_CLK_ENABLE();
/* Enable USARTx clock */
USART1_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USART1_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USART1_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
HAL_GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
#endif /* RT_USING_UART1 */
#if defined(RT_USING_UART2)
if (huart->Instance == USART2)
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
USART2_TX_GPIO_CLK_ENABLE();
USART2_RX_GPIO_CLK_ENABLE();
/* Enable USARTx clock */
USART2_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USART2_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(USART2_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USART2_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
HAL_GPIO_Init(USART2_RX_GPIO_PORT, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART2_IRQn);
}
#endif /* RT_USING_UART2 */
}
/**
* @brief UART MSP De-Initialization
* This function frees the hardware resources used in this example:
* - Disable the Peripheral's clock
* - Revert GPIO and NVIC configuration to their default state
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
#if defined(RT_USING_UART1)
if (huart->Instance == USART1)
{
/*##-1- Reset peripherals ##################################################*/
USART1_FORCE_RESET();
USART1_RELEASE_RESET();
/*##-2- Disable peripherals and GPIO Clocks #################################*/
/* Configure UART Tx as alternate function */
HAL_GPIO_DeInit(USART1_TX_GPIO_PORT, USART1_TX_PIN);
/* Configure UART Rx as alternate function */
HAL_GPIO_DeInit(USART1_RX_GPIO_PORT, USART1_RX_PIN);
HAL_NVIC_DisableIRQ(USART1_IRQn);
}
#endif /* RT_USING_UART2 */
#if defined(RT_USING_UART2)
if (huart->Instance == USART2)
{
/*##-1- Reset peripherals ##################################################*/
USART2_FORCE_RESET();
USART2_RELEASE_RESET();
/*##-2- Disable peripherals and GPIO Clocks #################################*/
/* Configure UART Tx as alternate function */
HAL_GPIO_DeInit(USART2_TX_GPIO_PORT, USART2_TX_PIN);
/* Configure UART Rx as alternate function */
HAL_GPIO_DeInit(USART2_RX_GPIO_PORT, USART2_RX_PIN);
HAL_NVIC_DisableIRQ(USART2_IRQn);
}
#endif /* RT_USING_UART2 */
}
int hw_usart_init(void)
{
struct drv_uart *uart;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
#ifdef RT_USING_UART1
uart = &uart1;
uart->UartHandle.Instance = USART1;
serial1.ops = &drv_uart_ops;
serial1.config = config;
/* register UART1 device */
rt_hw_serial_register(&serial1, "uart1",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
#endif /* RT_USING_UART1 */
#ifdef RT_USING_UART2
uart = &uart2;
uart->UartHandle.Instance = USART2;
serial2.ops = &drv_uart_ops;
serial2.config = config;
/* register UART2 device */
rt_hw_serial_register(&serial2, "uart2",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
#endif /* RT_USING_UART2 */
return 0;
}
INIT_BOARD_EXPORT(hw_usart_init);
關注下上面程式碼的條件編譯,原檔案寫的有些亂,我在這裡整理了下。
【7】開啟board.c,定位到210行附近,加入系統時鐘使能,程式碼修改如下:
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
while(1);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
/**
* This function will initial STM32 board.
*/
void rt_hw_board_init()
{
HAL_Init();
/* Configure the system clock @ 72 Mhz */
SystemClock_Config();
__CRC_CLK_ENABLE();
hw_usart_init();
#ifdef RT_USING_HEAP
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#ifdef RT_USING_CONSOLE
rt_console_set_device(CONSOLE_DEVICE);
#endif
}
注意上面HAL_RCC_GetHCLKFreq()/1000是兩次systimer中斷間隔時間,相應地在rtconfig.h中也要修改成
/* Tick per Second */
#define RT_TICK_PER_SECOND 1000
還要注意下board.h檔案中的內容,不然在切換UART1和UART2時可能會有莫名其妙的錯誤
#include <stm32f1xx.h>
#include <stm32f1xx_hal.h>
// <o> Internal SRAM memory size[Kbytes] <8-64>
// <i>Default: 64
#define STM32_SRAM_SIZE 64
#define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)
// <o> Console on USART: <0=> no console <1=>USART 1 <2=>USART 2 <3=> USART 3
// <i>Default: 1
#define STM32_CONSOLE_USART 1
#if STM32_CONSOLE_USART == 0
#define CONSOLE_DEVICE "no"
#elif STM32_CONSOLE_USART == 1
#define CONSOLE_DEVICE "uart1"
#elif STM32_CONSOLE_USART == 2
#define CONSOLE_DEVICE "uart2"
#elif STM32_CONSOLE_USART == 3
#define CONSOLE_DEVICE "uart3"
#endif
【8】修改drv_led.h的引腳操作
#ifndef __DRV_LED_H
#define __DRV_LED_H
//#include "board.h"
#define rt_led_on() HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET)
#define rt_led_off() HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET)
int rt_led_hw_init(void);
#endif
【9】檢查下stm32f1xxx_hal_conf.h中的相關開關項,如果有的功能塊沒有開啟,會產生錯誤。
【10】檢查下rtconfig.h,可以把不相關的功能關掉,請確保#define RT_USING_UART1已經開啟。
【11】先在命令列中執行下scons --target=mdk5 -s重新生成下工程,當然前提是已經安裝了python 2.7.1 和scons 2.5.x。
重新生成工程以後,在keiMDK 5中開啟此工程,先嚐試編譯下,自行解決下編譯錯誤,正常情況下,可以編譯通過,下載到開發板之後,可以看到led燈閃爍,在序列終端中可以可看到rt-thread的版本資訊。