STM32

STM32是STMicroelectronics(意法半导体)推出的一系列基于ARM Cortex-M内核的32位微控制器(MCU)产品。这些微控制器提供了广泛的产品系列,覆盖了多种不同的性能和功能需求,适用于各种应用领域,包括工业控制、汽车电子、消费类电子、医疗设备等。

STM32系列微控制器以其高性能、低功耗、丰富的外设接口和灵活的开发工具而闻名。它们通常具有丰富的存储器、多种通信接口(如UART、SPI、I2C、CAN等)、模拟数字转换器(ADC)、定时器、PWM输出等功能,以满足不同应用场景下的需求。

STM32微控制器通常使用标准的ARM Cortex-M内核,包括Cortex-M0、M0+、M3、M4和M7等,这些内核具有不同的性能和功耗特性,可根据具体应用的需求进行选择。此外,STM32系列还提供了多种封装和引脚配置,以满足不同尺寸和集成度的要求。

STMicroelectronics为STM32系列提供了丰富的开发工具和支持资源,包括基于ARM开发环境的集成开发环境(IDE)、调试器、评估板和参考设计等。这些工具和资源有助于开发人员快速开发和部署他们的应用,并提供了全面的技术支持和文档资料,帮助用户充分发挥STM32微控制器的性能和功能优势。

串口设置的一般步骤可以总结为如下几个步骤:

1) 串口时钟使能, GPIO 时钟使能
2) 串口复位
3) GPIO 端口模式设置
4) 串口参数初始化
5) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
6) 使能串口
7) 编写中断处理函数

1.串口时钟使能。

串口是挂载在 APB2 下面的外设,所以使能函数为:RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);

2.串口复位。

void USART_DeInit(USART_TypeDef* USARTx);//串口复位

3.串口参数初始化。

串口初始化是通过 USART_Init()函数实现的,

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

USART_InitStructure.USART_BaudRate = bound; //波特率设置;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式

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_Init(USART1, &USART_InitStructure); //初始化串口

4.数据发送与接收。

发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR

发送:void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

接收:uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

STM32串口配置步骤

RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。

TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式: 1)读 USART_SR,写USART_DR。 2)直接向该位写 0。

在我们固件库函数里面,读取串口状态的函数是:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

例如我们要判断读寄存器是否非空(RXNE), 操作库函数的方法是:USART_GetFlagStatus(USART1, USART_FLAG_RXNE);我们要判断发送是否完成(TC),操作库函数的方法是:USART_GetFlagStatus(USART1, USART_FLAG_TC);

6.串口使能。

串口使能是通过函数 USART_Cmd()来实现的,这个很容易理解,使用方法是:
USART_Cmd(USART1, ENABLE); //使能串口

7.开启串口响应中断。

有些时候当我们还需要开启串口中断,那么我们还需要使能串口中断,使能串口中断的函数是:
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT,FunctionalState NewState)

比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断,那么我们开启中断的方法是:USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断我们在发送数据结束的时候(TC, 发送完成) 要产生中断,那么方法是:USART_ITConfig(USART1, USART_IT_TC, ENABLE);

8.获取相应中断状态。

经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
比如我们使能了串口发送完成中断,那么当中断发生了, 我们便可以在中断处理函数中调用这个函数来判断到底是否是串口发送完成中断,方法是:USART_GetITStatus(USART1, USART_IT_TC)

转自: zengsf

围观 420

一、通信概述

按照数据传送方式分:

串行通信(一条数据线、适合远距离传输、控制较复杂)
并行通信(多条数据线、成本高、抗干扰性差)

按照通信的数据同步方式分:

异步通信(以1个字符为1帧、发送与接收时钟不一致)
同步通信(位同步、时钟一致)

按照数据的传输方向分:

单工(只能往一个方向传播)
半双工(数据传输可以沿两个方向,但是需要分时)
全双工(同时双向传输)

通信速率通常以比特率来表示,单位是:位/秒(bps),即每秒传输二进制代码的位数。之后会遇到一个波特率的概念,它表示每秒传输多少个码元。一般情况下,码元都是表示两种状态,即比特率=波特率。

二、串口通信

串口通信属于串行通信方式,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。在此基础上用户可以建立自己的高层通信协议。

串口通信的接口标准有很多,有RS-232、RS-232C、RS-422A、RS-485等。比较常用的就是RS-232和RS-485。

RS-232有两种接口:25针(DB25、标准)、9针(DB9、非标准),其逻辑电平如下:

在TxD和RxD上:

逻辑1(MARK)=-3V~-15V
逻辑0(SPACE)=+3~+15V

在RTS、CTS、DSR、DTR和DCD等控制线上:

信号有效(接通,ON状态,正电压)=+3V~+15V
信号无效(断开,OFF状态,负电压)=-3V~-15V

当stm32与计算机串口通信时,需要用电平转换芯片MAX232,进行TTL电平和RS-232电平的转换。

RS-232的通信协议比较简单,通常遵循96-N-8-1格式。其是全双工的,且是异步通讯。 

stm32之通信

RS485没有规定或推荐任何数据协议,用户根据需要自己建立高层通信协议。 

区别于RS232, RS485的特性包括:
1. RS-485的电气特性:采用“2线制”,半双工通信,逻辑“1”以两线间的电压差为+(2—6) V表示;逻辑“0”以两线间的电压差为-(2—6)V表示。接口信号电平比RS -232-C降低了,就不易损坏接口电路的芯片,且该电平与TTL电平兼容,可方便与TTL 电路连接,其收发器芯片一般采用SP3485。

2. RS-485的数据最高传输速率为10Mbps

3. RS-485接口是采用平衡驱动器和差分接收器的组合,抗共模干能力增强,即抗噪声干扰性好。

4. RS-485接口的最大传输距离标准值为4000英尺,实际上可达 3000米,另外RS-232-C接口在总线上只允许连接1个收发器,即单站能力。而 RS-485接口在总线上是允许连接多达128个收发器。即具有多站能力,这样用户可以利用单一的RS-485接口方便地建立起设备网络。 因RS-485接口具有良好的抗噪声干扰性,长的传输距离和多站能力等上述优点就使其成为首选的串行接口。因为RS485接口组成的半双工网络 ,一般只需二根连线,所以RS485接口均采用屏蔽双绞线传输。 RS485接口连接器采用DB-9的9芯插头座,与智能终端RS485接口采用DB-9(孔) ,与键盘连接的键盘接口RS485采用DB-9(针)。

在stm32中,我们会接触到USART的概念,即通用同步异步收发器,同步和异步主要看其时钟是否需要对外提供。其能够满足外部设备对串行通信的要求,只不过其是TTL电平,需要进行电平转换。

注:stm32的奇偶校验位是算在数据位中的(8位-9位),与PC不同。
注:串口用于传输ASCII码字符,我们进行数据传送时,要转换为对应ASCII码的16进制数或字符串。
注:TXE是指弹仓满,TC是指枪膛满。

三、I2C通信

I2C是两线式串行总线,接口少、控制简单、通信速率较高。I2C总线只有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL。

支持多主控多从控,不过同一时间点只能一个主控,连接节点数受地址限制。通过地址访问从控设备,通过仲裁决定主控设备优先级。因其采用时钟线,所以是同步传输。I2C还是半双工的。具体通信采用I2C的通信协议(寻址、起始/停止、应答等)。I2C用硬件实现起来较复杂,一般采用软件模拟I2C,移植方便。

stm32之通信

stm32之通信

四、CAN通信

CAN(Controller Area Network)是ISO国际标准化的串行通信协议。广泛应用于汽车、船舶等分布式控制系统。具有已经被大家认可的高性能和可靠性。CAN控制器通过组成总线的2根线(CAN-H和CAN-L)的电位差来确定总线的电平,在任一时刻,总线上有2种电平:显性电平和隐性电平。“显性”具有“优先”的意味,只要有一个单元输出显性电平,总线上即为显性电平,并且,“隐性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。(显性电平比隐性电平更强)。

总线上执行逻辑上的线“与”时,显性电平的逻辑值为“0”,隐性电平为“1”。

CAN总线是半双工的,虽然没有单独的时钟线,但是其采用位时序的方法进行同步传输。

CAN总线协议具有以下特点:

• 多主控制(ID仲裁)
• 系统的柔软性(没有地址信息)
• 通信速度快、距离远
• 具有错误检测、错误通知和错误恢复功能
• 故障封闭功能
• 连接节点多(理论上无限制,但是受总线时间延迟、电气负载影响,太多会降低速度)

CAN总线有两种标准如下图所示:

stm32之通信

CAN总线具有多节点可组网特性,如下图所示:
stm32之通信

从上面可以看出,CAN控制器(stm32芯片中带有)和CAN总线直接需要一个CAN收发器,可以采用TJA1040芯片。

CAN总线的工作原理

CAN总线使用串行数据传输方式,可以1Mb/s的速率在40m的双绞线上运行,也可以使用光缆连接,而且在这种总线上总线协议支持多主控制器。CAN与I2C总线的许多细节很类似,但也有一些明显的区别。当CAN总线上的一个节点(站)发送数据时,它以报文形式广播给网络中所有节点。对每个节点来说,无论数据是否是发给自己的,都对其进行接收。每组报文开头的11位字符为标识符,定义了报文的优先级,这种报文格式称为面向内容的编址方案。在同一系统中标识符是唯一的,不可能有两个站发送具有相同标识符的报文。当几个站同时竞争总线读取时,这种配置十分重要。当一个站要向其它站发送数据时,该站的CPU将要发送的数据和自己的标识符传送给本站的CAN芯片,并处于准备状态;当它收到总线分配时,转为发送报文状态。CAN芯片将数据根据协议组织成一定的报文格式发出,这时网上的其它站处于接收状态。每个处于接收状态的站对接收到的报文进行检测,判断这些报文是否是发给自己的,以确定是否接收它。由于CAN总线是一种面向内容的编址方案,因此很容易建立高水准的控制系统并灵活地进行配置。我们可以很容易地在CAN总线中加进一些新站而无需在硬件或软件上进行修改。当所提供的新站是纯数据接收设备时,数据传输协议不要求独立的部分有物理目的地址。它允许分布过程同步化,即总线上控制器需要测量数据时,可由网上获得,而无须每个控制器都有自己独立的传感器。

五、SPI通信

SPI 是Serial Peripheral Interface的缩写,直译为串行外围设备接口,SPI是Motorola公司推出的一种同步串行通讯方式,是一种四线同步总线,因其硬件功能很强,与SPI有关的软件就相当简单,使MCU有更多的时间处理其他事务。SPI内部结构简易图如下图所示:

stm32之通信

SPI接口一般使用4条线通信,分别如下:

• MISO:主设备输入/从设备输出
• MOSI:主设备输出/从设备输入
• SCLK:时钟信号线
• CS:从设备选择信号线

SPI一般用于一主多从,其结构示意图如下图所示:

stm32之通信

此外,SPI通信有4种不同的模式。下图是一种模式下的时序图:
stm32之通信

六、I2S通信

I2S是数字音频总线,在嵌入式音频系统设计中,并不是所有的MCU都支持I2S总线格式,再加上I2S还没有统一的接口标准,不同的厂家生产的设备接口也是五花八门,采用软件模拟实现I2S总线可有效解决在不支持其的MCU和设备之间通过I2S总线实现数据传输时出现的问题。

I2S为三线总线,3个信号分别为:

(1)串行时钟SCK,也叫位时钟(BCK)。即每发送1位数字音频数据,SCK上都有1个脉冲。SCK的频率=2×采样频率×采样位数。在数据传输过程中,I2S总线的发送器和接收器都可以作为系统的主机来提供系统的时钟频率。

(2)帧时钟WS,即命令(声道)选择,用于切换左右声道的数据。WS的频率等于采样频率,由系统主机提供。WS为“1”表示传输的是左声道的数据,WS为“0”表示传输的是右声道的数据。

(3)串行数据信号SD,用于传输二进制补码表示的音频数据。

I2S格式的信号无论有多少位有效数据,数据位的最高位(MSB)总是被最先传输,1次能够发送的数据决定于I2S格式的有效位数。

如下图所示为典型的时序图:

stm32之通信

七、USB通信

USB(Universal Serial Bus)是一种新的PC串行通信协议。是PC体系中的一套较新的工业标准,它支持单个主机与多个外设同时进行数据交换,大大满足了当今计算机外设追求高速度和高通用性的要求。

PC上的USB主机包括3个部分:USB主控制器/根Hub,USB系统软件和用户软件。下图是完整的USB系统组成。

stm32之通信

USB主机与设备之间的传输过程是这样的:在PC上,设备驱动程序通过调用USB驱动程序USBD,发出输入输出请求包IRP;这样,在USB驱动程序接到请求之后,调用主控制器驱动程序HCD,将IRP转化为USB的传输。当然,一个IRP可以包含一个或多个USB传输;接着,主控制器驱动程序将USB传输分解为总线事务,主控制器以包的形式发送给设备。  

USB设备类协议(USB DevICe Class Specification)与USB协议是互为补充的。针对USB的每一种设备类,都有一套特殊的设备类协议。正是USB采用了设备类的方式来对各种设备进行分类,才使USB总线能够有效的控制和管理各种设备,也使得各种设备的开发变的规范、简便。

此外,USB OTG既可以充当主机,也可以充当设备。

八、其他通信

比如无线通信、以太网通信。

转自: steed

围观 310

前段时间由于应用需要对产品授权进行限制,所以研究了一下有关STM32 MCU的唯一ID的资料,并最终利用它实现了我们的目标。

1、基本描述

在STM32的全系列MCU中均有一个96位的唯一设备标识符。在ST的相关资料中,对其功能的描述有3各方面:

• 用作序列号(例如 USB 字符串序列号或其它终端应用程序)
• 在对内部 Flash 进行编程前将唯一 ID 与软件加密原语和协议结合使用时用作安全密钥以提高 Flash 中代码的安全性
• 激活安全自举过程等

在资料中对其特性的描述是:96 位的唯一设备标识符提供了一个对于任何设备和任何上下文都唯一的参考号码。用户永远不能改变这些位。96 位的唯一设备标识符也可以以单字节/半字/字等不同方式读取,然后使用自定义算法连接起来。

想要读取唯一ID,就需要知道它的存储地址,在不同系列的MCU中地址是有差别的,我们查询了部分MCU的资料并将其总结如下:

如何获取STM32 MCU的唯一ID

2、获取唯一ID

前面我们对唯一ID做了简单的描述,并且得到了其存储地址,接下来我们说以说如何得到这个ID。

前面已经描述过唯一ID可以按字节、半字、字等方式读取。唯一ID是一个96位的信息串,所以按字读取就是3个字,按半字读取就是6个,按字节读取就是12个。本质上没有区别,在这里我们按字读取。

/*定义STM32 MCU的类型*/
typedef enum {
  STM32F0,
  STM32F1,
  STM32F2,
  STM32F3,
  STM32F4,
  STM32F7,
  STM32L0,
  STM32L1,
  STM32L4,
  STM32H7,
}MCUTypedef;

 
uint32_t idAddr[]={0x1FFFF7AC,  /*STM32F0唯一ID起始地址*/
                0x1FFFF7E8,  /*STM32F1唯一ID起始地址*/
                0x1FFF7A10,  /*STM32F2唯一ID起始地址*/
                0x1FFFF7AC,  /*STM32F3唯一ID起始地址*/
                0x1FFF7A10,  /*STM32F4唯一ID起始地址*/
                0x1FF0F420,  /*STM32F7唯一ID起始地址*/
                0x1FF80050,  /*STM32L0唯一ID起始地址*/
                0x1FF80050,  /*STM32L1唯一ID起始地址*/
                0x1FFF7590,  /*STM32L4唯一ID起始地址*/
                0x1FF0F420}; /*STM32H7唯一ID起始地址*/
 
/*获取MCU的唯一ID*/
void GetSTM32MCUID(uint32_t *id,MCUTypedef type)
{
  if(id!=NULL)
  {
    id[0]=*(uint32_t*)(idAddr[type]);
    id[1]=*(uint32_t*)(idAddr[type]+4);
    id[2]=*(uint32_t*)(idAddr[type]+8);
  }
}

3、使用唯一ID

我们得到唯一ID当然是为了使用它,前面在ST资料中描述了三个使用方式。我们在这里来使用它实现软件权限的限制。那么如何用唯一ID来实现软件运行权限的限制呢?我们说一说思路:

首先,我们需要指定一个Flash地址,至于于地址空间的大小则与我们xu要存储的信息有关,一般都不会太长。例如,我们使用MD5来生成加密信息,则最多需要16个字节的存储空间;如果我们使用SHA1来作为生成算法,则最多需要20个字节的空间。当然,我们也可以选取其中的一段或几段。不管选用多大的空间都炫耀将其清零,即初始化为0xFFFFFFFF。

接下来再程序运行前读取前面指定的地址并读取其值,并判断是否全部为0xFFFFFFFF,即判断程序是否第一次运行。如果是,那么就获取唯一ID并作相应的处理,然后将信息写入前面的地址中。

如果不是第一次运行,则读取指定地址的值,并用同样的算法处理唯一ID。然后比较存储的信息与计算的信息是否一致,一致则启动程序运行,不一致则终止运行。

如果有人使用工具读出FLASH内容时,因为改制定的地址已经被写入了信息,所以如果把读出的文件再烧到其它MCU芯片,因唯一ID不同所以信息完全不符程序就不会运行。从而实现了对程序权限的限制。

转自: foxclever

围观 508

1 前言

客户反馈在批量生产阶段,发现部分产品的 MCU 的 RTC 在低温(0℃)下工作不正常,但是在常温下又是正常的,且其他正常的 MCU 的 RTC 在常温与低温下都是正常的。

2 问题跟进与分析

通过与客户邮件沟通,了解到客户使用的 MCU 型号是:STM32F030C6T6TR。在产品的主从结构中主要用作电源管理和时钟管理。通过客户的描述,似乎相同型号不同片子都存在较大的差异。

由于时间紧急,在了解到初步信息后立即拜访客户,针对客户认为有问题的 MCU 芯片做针对性试验。通过STM32CubMx 生成测试工程,分别使用 LSI(40K),LSE(32.768K),RTC 工作时每秒通过 LED1(PB5)取反一次(通过 LED1 灯是否闪烁来指示 RTC 是否工作正常),然后分别测量 OSC 管脚与 PA8 脚(输出 LSI 或 LSE),并对比 ST 官方的 NUCLEO-F030 板,最终测试结果如下:

STM32F030 低温下 RTC 不工作

通过测试结果,我们得到如下信息:

 当使用 LSI 时,无论常温还是低温下都能正常工作。
 当使用 LSE 时,常温下能正常工作,但在低温(0℃)时,RTC 不再工作(LED1 停止闪烁),且 PA8 管脚无输出,但保持为高电平,且此时 OSC 管脚此时是存在 32.768K 的波形的。
 通过修改负载电容 C1&C2 的电容值从 5.1pF 修改到 6.8pF 时,原本低温下不工作的 RTC 又能恢复正常工作。

 对比 ST 官方的 NUCLEO-F030 板子,在常温与低温下均能正常工作。

STM32F030 低温下 RTC 不工作

STM32F030 低温下 RTC 不工作

从测试结果来看,通过修改负载电容的方式能让原本不能正常工作的 RTC 恢复正常工作,这个似乎为客户的负载电容不能精准的匹配系统的原因所致。

但客户对于这种解释是不接受的,理由是现在设计的负载电容 5.1pF 是通过测试后的值,精度可以达到 6.5ppm,但如果改为 6.8pF,那么精度将会变到大约 30ppm,这个会影响到 MCU 的 RTC 的时间精准度,系统在长时间运行后,时间必然会偏差很大,超出设计合理范围,这个是不允许的。

3 问题分析

既然客户不接受修改负载电容,那么首先我们重新梳理下客户的晶振设计各种参数是否准确,客户的 LSE 电路设计如下所示:

STM32F030 低温下 RTC 不工作

如上图,图中的 MR10 10Mohm 这个反馈电阻在实际电路中是没有加的,晶振使用的是 TXC 的,从晶振厂商提供的数据手册中得到相关参数如下:
STM32F030 低温下 RTC 不工作

再者,由于客户代码中使用的 LSE drive 配置的是最高等级,从下图芯片对应的数据手册中可以找到对应的 gm值为 25uA/V,此时的驱动电流为 1.6uA:
STM32F030 低温下 RTC 不工作

上图有提到 AN2867 这个文档,于是我们打开这个文档,在 3.4 节,发现有这个要求:
STM32F030 低温下 RTC 不工作

也就是要求 gain margin 的值要求大于 5,这样晶振才能正常起振,那么 gain margin 又是如何计算的呢?接下来找到 gainmargin 的计算公式,如下:
STM32F030 低温下 RTC 不工作

其中 gm 就是图 4 中从数据手册中提到的跨导值,STM32F030 LSE 的不同驱动等级对应着不同的 gm 值,由于我们的测试代码使用的是 CubeMx 自动生成的代码,其默认使用的是最高等级,且客户使用的也是最高等级,因此,这个得出的 gm 值为 25 uA/V, gm 有了,那么上面公式中的 gmcrit 又该如何计算,我们接下来找到它的计算公式,如:
STM32F030 低温下 RTC 不工作

通过晶振对应参数,我们可以得出:
ESR =70KΩ, C0 =1.0pF, CL =7.0pF,而 F 就是 LSE 的频率,为 32.768KHz.
于是:
g_mcrit =4 * 7E4 * POWER(2*PI()*32768,2) * POWER ((1.0E-12 + 7.0E-12),2) =7.6E-07
最终得到:
gain_magin =gm/g_mcrit =2.5E-05/7.6E-07 =32.89
这个值是远大于 5,因此,理论上不会存在晶振不起振是的问题,实际上当在低温下,之前在测试中也有发现晶振也是有起振,有波形输出的,只不过 PA8 脚没有波形输出,那个又是什么问题呢?

提交给 division,最终定位到 LSE 的驱动等级过高,在 AN2867 这个文档中,有这样的描述:

STM32F030 低温下 RTC 不工作

也就是说,在 STM32F0 和 STM32F3 中,当使用最高驱动模式(gm_crit_max=5uA/V, 见 Figure9 gm_crit_max)时,对应地应该只使用在 CL=12.5pF 的晶振上,以此避免振荡回路饱和,从而导致启动失败。若此时使用了一个较小的 CL(如 CL=6pF),那么会导致振荡频率不稳定和工作周期可能被扭曲。
AN2867 随后给出了一张表,列出了驱动等级与 gm_min、gm_crit_max 的关系,如下:
STM32F030 低温下 RTC 不工作

如上图,对于 STM32F0,当使用最高驱动模式 High 时,此时的 gm_min=25 uA/V,这个与数据手册中是一致的,另外 gm_crit_max =5uA/V,正是上面所描述的。

也就是说,在使用最高驱动模式下,此时与之对应的 CL 应该使用 12.5pF,而客户所使用的 CL 是 7pF,这个与手册AN2867 的建议内容是不相符的。从图 4 可以看出,在最高驱动等级模式下,此时驱动电流最大(1.6uA),但这里使用了一个比较小的负载电容(CL=7pF),按 AN2867 所述,此时有可能导致振荡回路饱和,振荡不稳定,工作周期扭曲。

此时,应该对应地下调这个 LSE 驱动等级,减小驱动电流,这里有 4 档(见 Figure 9):Low,Medium Low,Medium High,High。 目前使用的是 High,正是它出了问题,为保守起见,使用 Medium High 相对合适。

打开 STM32F030 的参考手册,在 7.4.9 节中:

STM32F030 低温下 RTC 不工作

如上图,将 LSEDRV[1:0]这两个为修改为 10 即可,将原先低温下 RTC 有问题的 MCU 芯片修改后再次放到低温下进行验证,测试结果为正常。由于此问题是部分芯片有可能会出现的问题,客户需要对修改后的芯片进行持续跟踪,至今没有再反馈出现过此问题,由此,此问题基本算是解决。

另外,从图 1 中所作的测试结果来看,实际上,在低温条件下,RTC 出现问题的时候,OSC pin 还是能正常捕捉到波形,只不过,PA8 脚这个 MCO 上没有波形,只是维持在高电平。于是,对于驱动电流过大所导致的振荡回路饱和,振荡不稳定,工作周期扭曲,这里理解为 MCO 脚与 MCU 内部振荡回路的连接点,也就是 MCO 所表现的波形。

总结

AN2867 这个文档总结了关于 STM32 晶振匹配方面的信息。里边有提到,负载电容 CL 值越大,所需的驱动电流也就越大,但牵引度越小。这也就解释了表 1 中通过增大 C1&C2 的电容值,原本出现问题的 RTC 能恢复正常的现象,这是由于 C1&C2 的电容值变大将导致负载电容 CL 变大,进而对应所需的驱动电流也就跟着增加,这反而减少了在高驱动模式情况下振荡回路出现饱和的机会。

来源:www.stmcu.com

围观 530

意法半导体专门配置的两个STM32探索套件让物联网设备能够通过2G/3G或LTE Cat M1/NB1网络快速连接云服务,让大众市场开发人员更自由、更灵活地开发应用。

每款套件都包括一个STM32L496探索板和集成一个Quectel蜂窝移动网络调制解调器的STMod+ 蜂窝扩展板。配套软件包括X-CUBE-CLD-GEN,这是一个移植到STM32L496超低功耗微控制器和扩展板的Espruino嵌入式JavaScript引擎,兼容STM32Cube生态系统。

硬件可直接使用,开发人员可以在JavaScript引擎上快速启动并定制脚本示例,无需额外投资。X-CUBE-CLD-GEN扩展套件支持STM32Cube软件工具、固件库和例程,有助于加快C代码开发,取得最佳的软件性能。

套件还可以接入意法半导体的合作伙伴提供的种类丰富的云服务,让用户有机会免费试用相关的第三方服务,建立、测试、部署和管理物联网设备和数据。意法半导体与市场领先的云服务提供商建立了合作伙伴关系,以解决物联网设备的关键需求,包括EMnify移动物联网连接和可编程SIM管理解决方案、Grovestreams云数据分析平台、 Exosite云物联网连接和解决方案平台、AVSystem Anjay LwM2M SDK和AVSystem Coiote云设备管理、支持Thingspeak云的Aimagin Matlab Blockset解决方案和Ubidots物联网应用开发平台。ST incard 嵌入式SIM解决方案基于ST33安全微控制器和STMod+扩展板,包含在133个国家提供数据和SMS连接的EMnify Profile。

Amarisoft LTE软件用于电信运营商在部署LTE Cat M1/NB1网络过程中调试LTE数据分组。

关于两个套件的配置,P-L496G-CELL01套件有一个Quectel UG96调制解调器,用于连接目前全球通用的2G/3G网络;P-L496G-CELL02支持新兴的LTE Cat M1/NB1 (NB-IoT)网络标准,向下兼容2G网络,采用BG96调制解调器。今后还将推出更多套件,进一步扩大大众市场覆盖率。

意法半导体在2月27日-3月1日德国纽伦堡Embedded World 2018展会第4A展厅138-238展台演示了这两个套件。

咨询产品价格,索取样品,请联系意法半导体销售代表处,或者访问 http://www.st.com/stm32l4-discovery 了解详细信息。

围观 311

使用范围

DMA(直接存储器存取)提供在外设与存储器之间或者存储器和存储器之间的高速数据传输使用。

这里的外设指的是32的外设,比如spi、usart、iic、adc等基于APB1 、APB2或AHB时钟的外设,而这里的存储器包括32自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问的源或者目的。

外部存储设备其自身在这就是外设了,配置时属于外设,不要与配置寄存器的存储设备混淆。
  
DMA和CPU分时使用内存
  
三种方法:

• 停止CPU访问内存;
• 周期挪用;
• DMA与CPU交替访问内存。

停止CPU访问内存
  
当外围设备要求传送一批数据时,由DMA控制器发一个停止信号给CPU,要求CPU放弃对地址总线、数据总线和有关控制总线的使用权。DMA控制器获得总线控制权以后,开始进行数据传送。

在一批数据传送完毕后,DMA控制器通知CPU可以使用内存,并把总线控制权交还给CPU,图(a)是这种传送方式的时间图。很显然,在这种DMA传送过程中,CPU基本处于不工作状态或者说保持状态。

这些关于STM32 DMA的使用,你都知道吗?

优点:控制简单,它适用于数据传输率很高的设备进行成组传送。
  
缺点:在DMA控制器访内阶段,内存的效能没有充分发挥,相当一部分内存工作周期是空闲的。这是因为,外围设备传送两个数据之间的间隔一般总是大于内存存储周期,即使高速I/O设备也是如此。例如,软盘读出一个8位二进制数大约需要32us,而半导体内存的存储周期小于0.5us,因此许多空闲的存储周期不能被CPU利用。
  
周期挪用
  
当I/O设备没有DMA请求时,CPU按程序要求访问内存;一旦I/O设备有DMA请求,则由I/O设备挪用一个或几个内存周期。
  
这种传送方式的时间图如下图(b):

这些关于STM32 DMA的使用,你都知道吗?

I/O设备要求DMA传送时可能遇到两种情况:

• 此时CPU不需要访内,如CPU正在执行乘法指令。由于乘法指令执行时间较长,此时I/O访内与CPU访内没有冲突,即I/O设备挪用一二个内存周期对CPU执行程序没有任何影响。

  
• I/O设备要求访内时CPU也要求访内,这就产生了访内冲突,在这种情况下I/O设备访内优先,因为I/O访内有时间要求,前一个I/O数据必须在下一个访问请求到来之前存取完毕。

显然,在这种情况下I/O 设备挪用一二个内存周期,意味着CPU延缓了对指令的执行,或者更明确地说,在CPU执行访内指令的过程中插入DMA请求,挪用了一二个内存周期。

与停止CPU访内的DMA方法比较,周期挪用的方法既实现了I/O传送,又较好地发挥了内存和CPU的效率,是一种广泛采用的方法。

但是I/O设备每一次周期挪用都有申请总线控制权、建立线控制权和归还总线控制权的过程,所以传送一个字对内存来说要占用一个周期,但对DMA控制器来说一般要2—5个内存周期(视逻辑线路的延迟而定)。

因此,周期挪用的方法适用于I/O设备读写周期大于内存存储周期的情况。
  
DMA与CPU交替访问内存
  
如果CPU的工作周期比内存存取周期长很多,此时采用交替访内的方法可以使DMA传送和CPU同时发挥最高的效率。
  
这种传送方式的时间图如下:

这些关于STM32 DMA的使用,你都知道吗?

假设CPU工作周期为1.2us,内存存取周期小于0.6us,那么一个CPU周期可分为C1和C2两个分周期,其中C1专供DMA控制器访内,C2专供CPU访内。
  
这种方式不需要总线使用权的申请、建立和归还过程,总线使用权是通过C1和C2分时制的。CPU和DMA控制器各自有自己的访内地址寄存器、数据寄存器和读/写信号等控制寄存器。

在C1周期中,如果DMA控制器有访内请求,可将地址、数据等信号送到总线上。在C2周期中,如CPU有访内请求,同样传送地址、数据等信号。

事实上,对于总线,这是用C1,C2控制的一个多路转换器,这种总线控制权的转移几乎不需要什么时间,所以对DMA传送来讲效率是很高的。

这种传送方式又称为“透明的DMA”方式,其来由是这种DMA传送对CPU来说,如同透明的玻璃一般,没有任何感觉或影响。在透明的DMA方式下工作,CPU既不停止主程序的运行,也不进入等待状态,是一种高效率的工作方式。当然,相应的硬件逻辑也就更加复杂。

非循环方式传输

STM32使用DMA非循环方式传输完成后重新开启传输:通道配置为非循环模式时,传输结束后(即传输计数变为0)将不再产生DMA操作。要开始新的DMA传输,需要在关闭DMA通道的情况下,在DMA_CNDTRx寄存器中重新写入传输数目。
  
即关DMA->写传输数目->开DMA。
 
存储器到存储器模式
  
DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。

以串口为例,这种外设查看串口使能DMA时序可知其会自动向CPU提DMA请求,而对于比如外设也是存储设备那么他自身不具有自动提DMA申请功能,这种就属于存储器到存储器模式,这是m2m位需置1。

这些关于STM32 DMA的使用,你都知道吗?

以上图DMA1请求映像为例,可知外设(这里指的是比如串口spi TIM等32自带的外设)都是以硬件自动触发的DMA请求,而非自身外设比如加的外部存储设备无硬件自动触发机制就需要通过设置M2M位实现软件触发DMA请求给CPU了当设置了DMA_CCRx寄存器中的MEM2MEM位之后,在软件设置了DMA_CCRx寄存器中的EN位启动DMA通道时, DMA传输将马上开始。

当DMA_CNDTRx寄存器变为0时, DMA传输结束。存储器到存储器模式不能与循环模式同时使用。

来源: 电子产品世界

围观 532

DMA(Direct Memory Access)常译为“存储器直接存取”。早在Intel的8086平台上就有了DMA应用了。

一个完整的微控制器通常由CPU、存储器和外设等组件构成。这些组件一般在结构和功能上都是独立的,而各个组件的协调和交互就由CPU完成。如此一来,CPU作为整个芯片的核心,其处理的工作量是很大的。如果CPU先从A外设拿到一个数据送给B外设使用,同时C外设又需要D外设提供一个数据。。。这样的数据搬运工作将使CPU的负荷显得相当繁重。

严格的说,搬运数据只是CPU的比较不重要的一种工作。CPU最重要的工作室进行数据运算,从加减乘除到一些高级的运算,包括浮点、积分、微分、FFT等。CPU还需要负责复杂的中断申请和响应,以保证芯片的实时性能。

理论上常见的控制外设,比如Usart、I2C、SPI甚至是USB等通信接口,单纯的利用CPU进行协议模拟也是可以实现的,比如51单片机经常使用I/O口模拟I2C协议通信。但这样既浪费了CPU的资源,同时实现后的性能表现往往和使用专门的硬件模块实现的效果相差甚远。从这个角度来看,各个外设控制器的存在,无疑降低了CPU的负担,解放了CPU的资源。

数据搬运这一工作占用了大部分的CPU资源,成为了降低CPU的工作效率的主要原因之一。于是需要一种硬件结构分担CPU这一职能—— DMA。

从数据搬运的角度看,如果要把存储地址A的数值赋给另外一个地址上B的变量,CPU实现过程为首先读出A地址上的数据存储在一个中间变量,然后再转送到B地址的变量上。使用DMA则不需要中间变量,直接将A地址的数值传送到B地址的变量里。无疑减轻了CPU的负担,也提高了数据搬运的效率。

stm32中 DMA1有7个通道,DMA2有5个通道。DMA挂载的时钟为AHB总线,其时钟为72Mhz,所以可以实现高速数据搬运。

聊聊STM32中DMA模块的使用

stm32使用DMA的相关操作:

1、DMA的配置

void DMA_Configuration(void){ DMA_InitTypeDefDMA_InitStructure; //DMA设置: //设置DMA源:内存地址&串口数据寄存器地址 //方向:内存-->外设 //每次传输位:8bit //传输大小DMA_BufferSize=SENDBUFF_SIZE //地址自增模式:外设地址不增,内存地址自增1 //DMA模式:一次传输,非循环 //优先级:中 DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4 DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端 DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular(不停地传送) DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等) DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel4, &DMA_InitStructure);}

注:

1、传输通道:
通过查表,串口1的发送对应的是DMA的通道4,所以此处选择通道4.

2、DMA传输方式:
(1)DMA_Mode_Normal,正常模式,当一次DMA数据传输完后,停止DMA传送,对于上例而言,就是DMA_PeripheralDataSize_Byte个字节的传送完成后,就停止传送。

(2) DMA_Mode_Circular

循环模式,当传输完一次后,重新接着传送,永不停息。

2、外设的DMA方式设置
将串口1设置成DMA模式:

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待传输数据的定义和初始化
#define SENDBUFF_SIZE 10240vu8 SendBuff[SENDBUFF_SIZE];

for(i=0;i

4、开始DMA传输(使能对应的DMA通道) DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA传输的完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) { LED_1_REV; //LED翻转 Delay(); //浪费时间 }

当传输完成后,就会跳出上面的死循环。

来源: 21ic电子网

围观 910

支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在 CM3 中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

位带操作的概念其实 30 年前就有了,那还是8051 单片机开创的先河,如今,CM3 将此能力进化,这里的位带操作是 8051 位寻址区的威力大幅加强版。

CM3 使用如下术语来表示位带存储的相关地址:

位带区:支持位带操作的地址区

位带别名:对别名地址的访问最终作用到位带区的访问上(这中途有一个地址映射过程)

在位带区中,每个比特都映射到别名地址区的一个字——这是只有 LSB 有效的字。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。

STM32中的位带(bit-band)操作

STM32中的位带(bit-band)操作

STM32中的位带(bit-band)操作

支持位带操作的两个内存区的范围是:
0x2000_0000‐0x200F_FFFF(SRAM 区中的最低 1MB)
0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB)

对 SRAM 位带区的某个比特,记它所在字节地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:

AliasAddr=0x22000000+((A-0x20000000)*8+n)*4=0x22000000+(A-0x20000000)*32+n*4

对于片上外设位带区的某个比特,记它所在字节的地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:

AliasAddr=0x42000000+((A-0x40000000)*8+n)*4=0x42000000+(A-0x40000000)*32+n*4

上式中,“*4”表示一个字为 4 个字节,“*8”表示一个字节中有 8 个比特。

这里再不嫌啰嗦地举一个例子:

1. 在地址 0x20000000 处写入 0x3355AACC
2. 读取地址0x22000008。本次读访问将读取 0x20000000,并提取比特 2,值为 1。
3. 往地址 0x22000008 处写 0。本次操作将被映射成对地址 0x20000000 的“读-改-写”操作(原子的),把比特2 清 0。
4. 现在再读取 0x20000000,将返回 0x3355AAC8(bit[2]已清零)。

位带别名区的字只有 LSB 有意义。另外,在访问位带别名区时,不管使用哪一种长度的数据传送指令(字/半字/字节),都把地址对齐到字的边界上,否则会产生不可预料的结果。

///////////////////////////////////////////////////////////////
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考《CM3权威指南》第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C

#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入

#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入

#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入

#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入

#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入

#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入

#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入

出处:http://www.cnblogs.com/yuandongtao1989/p/6804318.html

围观 426

页面

订阅 RSS - STM32