编写本文稿的目的,在于通过分析stm32平台上的串口中断源码,学习
-
RTT中如何编写中断处理程序
-
如何编写RTT设备驱动接口代码
-
了解串行设备的常见处理机制
先以RTT官方源码中的STM32 BSP包来分析。rt-thread\bsp\stm32f10x 下,涉及的文件为:
-
usart.c
-
usart.h
-
serail.c
-
serail.h
RTT的设备驱动程序概述
编写uart的驱动程序,首先需要了解RTT的设备框架,RTT的设备框架我们已经大致的介绍了一下,这里以usart的驱动来具体分析RTT的IO设备管理。注:参考《RTT实时操作系统编程指南》 I/O设备管理一章。
我们可以将USART的硬件驱动分成两个部分,如下图所示
+----------------------+
| rtt下的usart设备驱动 |
|---------------------- |
| usart硬件初始化代码 |
|---------------------- |
| usart 硬件 |
+----------------------+
实际上,在缺乏操作系统的平台,即裸机平台上,我们通常只需要编写USART硬件初始化代码即可。而引入了RTOS,如RTT后,RTT中自带IO设备管理层,它是为了将各种各样的硬件设备封装成具有统一的接口的逻辑设备,以方便管理及使用。
让我们从下向上看,先来看看USART硬件初始化程序,这部分代码位于usart.c和usart.h中。
USART硬件初始化
假如在接触RTT之前,你已经对stm32很熟悉了,那么此文件中定义的函数名一定让你倍感亲切。这里实现的函数有:
-
static void RCC_Configuration(void);
-
static void GPIO_Configuration(void);
-
static void NVIC_Configuration(void);
-
static void DMA_Configuration(void);
-
void rt_hw_usart_init();
前四个函数,是跟ST官方固件库提供的示例代码的名字保持一致。这些函数内部也是直接调用官方库代码实现的。具体不再赘述。
对STM32裸机开发尚不太熟悉的朋友,建议先去官方网站下载官方固件源码包,以及应用手册和示例程序,ST提供了大量的文档和示例代码,利用好这些资源可以极大地加快开发。
现在来重点关注一下最后一个函数,即 rt_hw_usart_init函数的实现。
/* * Init all related hardware in here * rt_hw_serial_init() will register all supported USART device */ void rt_hw_usart_init() { USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration(); DMA_Configuration(); /* uart init */ #ifdef RT_USING_UART1 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; USART_Init(USART1, &USART_InitStructure); USART_ClockInit(USART1, &USART_ClockInitStructure); /* register uart1 */ rt_hw_serial_register(&uart1_device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, &uart1); /* enable interrupt */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); #endif #ifdef RT_USING_UART2 .... #endif #ifdef RT_USING_UART3 .... #endif }
上述代码中,大部分代码都是调用ST库函数,请注意下列语句。
/* register uart1 */ rt_hw_serial_register(&uart1_device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, &uart1);
这个函数的实现位于serial.c中,我们将在下一小节分析,暂且不表。
显然,函数rt_hw_usart_init,顾名思义,是用于初始化USART硬件的函数,因此这个函数一定会在USART使用之前被调用。搜索工程发现,这个函数是在board.c中rt_hw_board_init函数中被调用,而rt_hw_board_init函数又是在startup.c里的 rtthread_startup函数中调用的。进一步在startup.c的main函数中调用的,我们将实际的路径调用过程绘制如下。
startup.c main() ---> startup.c rtthread_startup() ---> board.c rt_hw_board_init() ---> usart.c rt_hw_usart_init()
到这里,USART硬件的初始化工作已经完成完成了99%,下一步,我们需要为USART编写代码,将其纳入到RTT的设备管理层之中,正如前面所说,这部分代码在serial.c中实现。我们来重点分析这一文件。