标签归档:stm32

STM32+UCOS-II实现临界区不关闭重要中断

在ARM7内核芯片中,在临界区不关闭快速中断,可以避免丢失重要的中断信号。STM32要实现类似功能,需要用到BASEPRI寄存器。

比如一个产品需要外接维根读头,STM32利用外部中断解码。如果在临界区关闭所有中断,那么在刷卡时,有可能丢掉部分外部中断信号,导致解码错误。

系统简化中断设置,只设置抢占式优先级,不要子优先级。抢占式优先级(0-15),子优先级都为0.

UCOS的SYSTICK中断及PENDSV中断设定在最低优先级

#define ConfigKERNEL_INTERRUPT_PRIORITY_PENSV (15)

#define ConfigKERNEL_INTERRUPT_PRIORITY_SYSTICK (14)

Pendsvde 的优先级在OS_CPU_A.S的OSStartHighRdy中设置,优先级最低为15.

Systick在core_cm3.h的systick_config()中设置,pendsv的优先级寄存器0Xe000ed22的值为0Xf0,抢占式优先级为15,亚优先级为0。Systick的优先级寄存器0XE000ED23的值为0Xe0,抢占式优先级为14,亚优先级为0.

维根读头的外部中断设置为0号抢占式优先级。

如果OS_ENTER_CRITIAL()函数,即OS_CPU_A.S中的OSCPUSAVESR如下

MRS R0,PRIMASK

CPSID I

BX LR

那么程序进入临界区后,所有外部中断都会关闭,包括维根读头使用的外部中断0,导致接收维根数据出错。这时应该使用BASEPRI寄存器。

BASEPRI寄存器最多有9位(由表达优先级的位数决定,STM32F103中,高4位有效),它定义了被屏蔽优先级的阈值。当它设定成某个值后,所有优先级大于等于此值的中断都被关(优先级号越大,优先级越低)。小于此值的中断不会被关闭。若设成0,则不关闭任何中断,0是缺省值。

此处要保证维根读头使用的中断优先级0不被关闭,所以要设置BASEPRI高4位为1.

MASK_INTERRUPT_PRIORITY EQU 0X01

OSCPUSAVESR

MRS R0,BASEPRI

MOVS R1,#(MASK_INTERRUPT_PRIORITY<< 4)

MSR BASEPRI,R1

BX LR

OSCPURESTORESR

MSR BASEPRI,R0

BX LR

实际测试,这样改写后,接收的维根读头数据每次都正确。

STM32模拟16BIT并口驱动3.0’TFT屏(一)

ARM芯片使用的是STM32F105系列,没有FSMC接口,所以采用模拟16bit驱动TFT。TFT屏驱动芯片是SPFD5420A。3.0’屏,400*240大小。

SPFD5420A支持262144color,也就是屏资料介绍里常说的262K色或26万色。262144是怎么算出来的?我们先来了解TFT的显示原理。400*240的屏有96000个像素,每个像素的颜色由RGB三种颜色混合而成。SPFD5420A支持18bit接口,一个像素由R(6)G(6)B(6)共18位组成。如下所示:

R5

R4

R3

R2

R1

R0

G5

G4

G3

G2

G1

G0

B5

B4

B3

B2

B1

B0

那么一个像素能显示的颜色有2^18,也就是262144种颜色。

65K色屏一个像素由R(5)G(6)B(5)共16位组成,2^16=65536种颜色。

16.7M色屏一个像素由R(8)G(8)B(8)共24位组成,2^24=16777216种颜色。

这个参数和屏的大小无关,只和屏驱动芯片支持的RGB组合的位数有关。

SPFD5420A内部有233280byteGRAM,最大的像素为240*432,每个像素18bit,240*432*18/8=233280byte。

SPFD5420A支持8,9,16,18位并口通讯。SPFD5420D有一个16bit索引寄存器IR,一般作为存储器的指针使用。2个18bit数据寄存器,一个是写数据寄存器(WDR),一个是读数据寄存器(RDR)。

TFT屏接口图如下:

clip_image002

选择16bit模式,TFT的DB0和DB9脚没有使用,DB1-DB8接STM32的GPIOE的PIN0-PIN7脚,DB10-DB17接GPIOE的PIN8-PIN15脚。引脚定义如下:

#define TFT_CS GPIO_Pin_0

#define TFT_RS GPIO_Pin_1

#define TFT_RST GPIO_Pin_4

#define TFT_RD GPIO_Pin_5

#define TFT_MISO GPIO_Pin_6

#define TFT_MOSI GPIO_Pin_7

//————-PORTB———————

#define TFT_PCLK GPIO_Pin_12

#define TFT_DE GPIO_Pin_13

#define TFT_WR GPIO_Pin_14

#define TFT_HSYNC GPIO_Pin_15

//————-PORTC———————

#define TFT_BACKLIGHT GPIO_Pin_9

//————-PORTE———————

#define TFT_DATAPORT GPIOE

#define Lcd_Light_ON GPIOC->BSRR = GPIO_Pin_9;

#define Lcd_Light_OFF GPIOC->BRR = GPIO_Pin_9;

#define Set_Cs GPIO_SetBits(GPIOA,GPIO_Pin_0);

#define Clr_Cs GPIO_ResetBits(GPIOA,GPIO_Pin_0);

#define Set_Rs GPIO_SetBits(GPIOA,GPIO_Pin_1);

#define Clr_Rs GPIO_ResetBits(GPIOA,GPIO_Pin_1);

#define Set_nWr GPIO_SetBits(GPIOB,GPIO_Pin_14);

#define Clr_nWr GPIO_ResetBits(GPIOB,GPIO_Pin_14);

#define Set_nRd GPIO_SetBits(GPIOA,GPIO_Pin_5);

#define Clr_nRd GPIO_ResetBits(GPIOA,GPIO_Pin_5);

IO口初始化函数:

static void LCD_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = TFT_CS|TFT_RS |TFT_WR|TFT_RST|TFT_RD;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = TFT_WR;

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = TFT_BACKLIGHT;

GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;

GPIO_Init(GPIOE, &GPIO_InitStructure);

/* tft control gpio init */

GPIO_SetBits(GPIOA, TFT_RST); // RST

GPIO_SetBits(GPIOA, TFT_RD); // RD = 1

GPIO_SetBits(GPIOB, TFT_WR); // WR = 1

GPIO_SetBits(GPIOA, TFT_RS); // RS

GPIO_SetBits(GPIOA, TFT_CS); //CS = 1

}

STM32驱动不带字库12864LCD

STM32驱动5V的12864LCD,控制脚和数据较最好接到STM32能容忍5v的IO口,外加上拉电阻时,控制脚和数据脚设置成开漏输出。不加上拉电阻时,控制脚设置为推拉输出,数据脚输出时,设置成推拉输出,输入时设置成上拉输入。加不加上拉电阻都能点亮LCD,关键是脚位配置。

GPIOE的PE0-PE7做数据线,控制线定义如下:

//————-PORTE———————

#define R_S GPIO_Pin_8

#define R_W GPIO_Pin_9

#define EN GPIO_Pin_10

#define _CS1 GPIO_Pin_11

#define _CS2 GPIO_Pin_12

#define _RST GPIO_Pin_13

首先IO口初始化

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOE, &GPIO_InitStructure);

GPIO_ResetBits(GPIOE, EN );

GPIO_SetBits(GPIOE,_CS1 | _CS2 );

注意_CS1,_CS2初始化是一定要拉高,否则检测忙信号时,忙信号会一直是高。我就是因为这个问题卡了好几天。

以下是LCD驱动程序:

//指令宏定义

#define Display_On 0x3f //显示开指令

#define Display_Off 0x3e //显示关指令

#define Y_Col_Addr 0x40 //定位到第0列指令(列起始地址)(0-63)

#define X_Page_Addr 0xb8 //定位到第0页指令(页起始地址)(0-7)

#define Start_Line 0xc0 //定位从DDROM中的第0行开始往屏幕上显示

继续阅读

STM32库起始文件堆栈分配(转帖)

定义大小在startup_stm32f10x_hd.s

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base

2.堆和栈位置

通过MAP文件可知

HEAP                                     0x200106f8   Section      512  startup_stm32f2xx.o(HEAP)
STACK                                    0x200108f8   Section     1024  startup_stm32f2xx.o(STACK)

__heap_base                              0x200106f8   Data           0  startup_stm32f2xx.o(HEAP)
__heap_limit                             0x200108f8   Data           0  startup_stm32f2xx.o(HEAP)
__initial_sp                             0x20010cf8   Data           0  startup_stm32f2xx.o(STACK)

显然 Cortex-m3资料可知:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)

显然堆和栈是相邻的。

3.堆和栈空间分配

栈:向低地址扩展

堆:向高地址扩展

显然如果依次定义变量

先定义的栈变量的内存地址比后定义的栈变量的内存地址要大

先定义的堆变量的内存地址比后定义的堆变量的内存地址要小 

4.堆和栈变量

栈:临时变量,退出该作用域就会自动释放

堆:malloc变量,通过free函数释放

另外:堆栈溢出,编译不会提示,需要注意

STM32串口发送时序图分析

下面是STM32使用手册上的串口发送时序图:

clip_image002

1、 使能串口发送TE,此时USART_DR为空,此时应查询TXE是否置1,TXE置1,TX脚先发送一个空闲帧,把F1帧写入USART_DR,TXE被清零。因为这时正在发送空闲帧,所以写入USART_DR的数据被放入TDR寄存器,还没有拷贝到移位寄存器。

2、 在空闲帧发送完后,TDR寄存器中的数据被拷贝到移位寄存器,此时应查询TXE是否置1,TXE置1,表示TDR已空,可以放入下一个数据。此时在TX脚上将会发送F1帧的数据,同时软件把F2帧的数据写入USART_DR,TXE被清零。

3、 在F1帧的停止位发送完后,因为TDR寄存器中的F2还没被拷入移位寄存器,所以此时TXE仍为0,TC不置1.此时应查询TXE是否置1,TXE置1,表示TDR已空,可以放入下一个数据。此时在TX脚上将会发送F2帧的数据,同时软件把F3帧的数据写入USART_DR,TXE被清零。

4、 在F2帧的停止位发送完后,因为TDR寄存器中的F3还没被拷入移位寄存器,所以此时TXE仍为0,TC不置1.此时应查询TXE是否置1,TXE置1,表示TDR已空,后面没有数据写入USART_DR,TXE保持高电平,此时在TX脚上将会发送F3帧的数据。

5、 在F3帧的停止位发送完后,因为此时TXE为1,所以TC标志会置1.如果TCIE为1,将会产生中断。

继续阅读