STM32

关于STM32对内部Flash的保护

为了防止对Flash的非法访问,所有STM32的芯片都提供对Flash的保护,具体分为写保护和读保护。

如果对Flash设置了写保护,那就无法对Flash进行编程和擦除。在开发STM32的时候,如果出现这种情况,通常仿真器都支持对Flash进行解锁,像jlink,stlink等仿真器都支持这个功能。

在使用MDK进行调试的时候,可能会遇到如下图所示的报错信息,这时候就要排查Flash是不是被保护起来了。 

1.png

读保护即大家通常说的“加密”,是作用于整个Flash存储区域,相关文章:STM32等单片机程序加密的方法。一旦设置了Flash的读保护,内置的Flash存储区只能通过程序的正常执行才能读出,而不能通过下述任何一种方式读出:

  • 通过调试器(JTAG或SWD)

  • 从RAM中启动并执行的程序

写保护是以四页(1KB/页) Flash存储区为单位提供写保护,对被保护的页实施编程或擦除操作将不被执行,同时产生操作错误标志,读与写设置的效果见下表: 
当Flash读保护生效时,CPU执行程序可以读受保护的Flash区,但存在两个例外情况:

2.png 

  • 调试执行程序时

  • 从RAM启动并执行程序时 

STM32还提供了一个特别的保护,即对Flash存储区施加读保护后,即使没有启用写保护,Flash的第 0 ~ 3 页也将处于写保护状态,这是为了防止修改复位或中断向量而跳转到RAM区执行非法程序代码。 

Flash保护的相关函数   

FLASH_Unlock();   //Flash解锁 
FLASH_ReadOutProtection(DISABLE);  //Flash读保护禁止   
FLASH_ReadOutProtection(ENABLE);   //Flash读保护允许

STM32如何设置读保护和解除读保护?

读保护设置后将不能读出Flash中的内容。
如何设置读保护在程序的开头加入“设置读保护”的代码即可,每次运行代码时都检查一下,如果没有开就打开,如果打开了就跳过。其中,设置读保护的代码如下:

int main(void)
{  
   ...
   if (FLASH_GetReadOutProtectionStatus()!=SET)//检查设置读保护与否  
   {    
      FLASH_Unlock();         //写保护时可以不用这句话,可用可不用    
      FLASH_ReadOutProtection(ENABLE);     //设置读保护  
   }  
   ...
   while(1)  
   {    
   ...  
   }
}

上面的代码执行后,使用j-link就不能读出程序了,实现了代码读保护。需要注意的是,芯片读保护后无法再次烧写新的程序到Flash中,必须要解除读保护才可以。但是当解除读保护的时候STM32会自动擦除整个Flash,起到保护数据的作用。

通过代码解除Flash保护
解除读保护可以设置在按键里面,方便实现解锁,也可以设置在命令中。如下是解除读保护代码:

3.png

程序中设置一个按键或者命令,可以随时解除Flash的读保护,让芯片又可以重新烧录程序。如果没有留,还可以专门写一个程序,下载到RAM中去运行,用来解除读保护。

注意:执行后,Flash会自动全部擦除。

int main(void)
{
   Chip_Init();  
   FLASH_Unlock(); //不解锁FALSH也可设置读保护,可用可不用  
   FLASH_ReadOutProtection(DISABLE);
}

通过ST-Link Utility来解除Flash保护

在STLink连接目标板的情况下打开程序烧写软件ST-Link Utility,在菜单栏的Target下选择connect,因为这时候Flash已经被锁住了,能看到如下图所示的错误提示。

4.png

下面来操作如何解除Flash保护。

请确保当前已经正确连接了STLink和目标板,在菜单栏Target里打开Option Bytes...选项,发现在这里Read Out Protection选项是Enable,这个表示无法通过SWD读取STM32内部Flash的程序。

5.png

将Read Out Protection选项设置为Disable,并点击Apply。

这时候Flash已经成功解锁了,跟上文提到的解除Flash保护的结果一样,内部Flash已经被擦除了,如下图红框中所示。

6.png

完成以上步骤之后,在菜单栏Target下选择Disconnect断开与目标板连接。

重新进入MDK,可以正常对目标板烧写程序了。

通过ST-Link Utility来设置Flash保护

7.png

在菜单栏Target里打开Option Bytes...选项,可以看到下面有Flash sector protection选项。选择Select all之后,发现所有Page的Protection项都已经变成Write Protection了,只要选择Apply选项就可以对Flash进行写保护,如上图所示。

来源:STM32嵌入式开发

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 12

前言

测试代码的运行时间的两种方法:

使用单片机内部定时器,在待测程序段的开始启动定时器,在待测程序段的结尾关闭定时器。为了测量的准确性,要进行多次测量,并进行平均取值。

借助示波器的方法是:在待测程序段的开始阶段使单片机的一个GPIO输出高电平,在待测程序段的结尾阶段再令这个GPIO输出低电平。用示波器通过检查高电平的时间长度,就知道了这段代码的运行时间。显然,借助于示波器的方法更为简便。

借助示波器方法的实例

Delay_us函数使用STM32系统滴答定时器实现:

#include "systick.h"
/* SystemFrequency / 1000    1ms中断一次 
 * SystemFrequency / 100000     10us中断一次 
 * SystemFrequency / 1000000 1us中断一次 
*/
#define SYSTICKPERIOD                    0.000001
#define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
/**  
  * @brief  读取SysTick的状态位COUNTFLAG  
  * @param  无  
  * @retval The new state of USART_FLAG (SET or RESET).  
*/
static FlagStatus SysTick_GetFlagStatus(void) 
{
 if(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk)     
     {
 return SET;    
     }
 else    
     {
 return RESET;    
     }
}

/**  
  * @brief  配置系统滴答定时器 SysTick  
  * @param  无  
  * @retval 1 = failed, 0 = successful  
  */
uint32_t SysTick_Init(void)
{
/* 设置定时周期为1us  */
if (SysTick_Config(SystemCoreClock / SYSTICKFREQUENCY))     
    { 
/* Capture error */
return (1);    
    }

/* 关闭滴答定时器且禁止中断  */    
   SysTick->CTRL &= ~ (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);                                                  
return (0);
}

/**  
  * @brief   us延时程序,10us为一个单位  
  * @param  
  *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us  
  * @retval  无  
  */

void Delay_us(__IO uint32_t nTime)
{     
/* 清零计数器并使能滴答定时器 */    
   SysTick->VAL   = 0;      
   SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;     

for( ; nTime > 0 ; nTime--)    
     {
/* 等待一个延时单位的结束 */
while(SysTick_GetFlagStatus() != SET);    
     }

/* 关闭滴答定时器 */    
   SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}

检验Delay_us执行时间中用到的GPIO(gpio.h、gpio.c)的配置:

#ifndef __GPIO_H
#define    __GPIO_H
#include "stm32f10x.h"

#define     LOW          0
#define     HIGH         1

/* 带参宏,可以像内联函数一样使用 */
#define TX(a)                if (a)    \ 
                                                    GPIO_SetBits(GPIOB,GPIO_Pin_0);\else        \                                            
                                                    GPIO_ResetBits(GPIOB,GPIO_Pin_0)void GPIO_Config(void);
#endif

#include "gpio.h"

/**  
  * @brief  初始化GPIO  
  * @param  无  
  * @retval 无  
  */

void GPIO_Config(void)
{        
/*定义一个GPIO_InitTypeDef类型的结构体*/        
          GPIO_InitTypeDef GPIO_InitStructure;

/*开启LED的外设时钟*/        
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); 
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         
        GPIO_Init(GPIOB, &GPIO_InitStructure);    
}

在main函数中检验Delay_us的执行时间:

1.png

示波器的观察结果:

2.png

3.png

可见Delay_us(100),执行了大概102us,而Delay_us(1)执行了2.2us。

更改一下main函数的延时参数:

4.png

示波器的观察结果:

5.png

6.png

可见Delay_us(100),执行了大概101us,而Delay_us(10)执行了11.4us。

结论:此延时函数基本上还是可靠的。

使用定时器方法的实例

Delay_us函数使用STM32定时器2实现:

#include "timer.h"

/* SystemFrequency / 1000            1ms中断一次 
 * SystemFrequency / 100000     10us中断一次 
 * SystemFrequency / 1000000         1us中断一次 
 */

 #define SYSTICKPERIOD                    0.000001
 #define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)

 /**  
   * @brief  定时器2的初始化,,定时周期1uS  
   * @param  无  
   * @retval 无  
   */

void TIM2_Init(void)
{    
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

/*AHB = 72MHz,RCC_CFGR的PPRE1 = 2,所以APB1 = 36MHz,TIM2CLK = APB1*2 = 72MHz */    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

/* Time base configuration */    
    TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/SYSTICKFREQUENCY -1;    
    TIM_TimeBaseStructure.TIM_Prescaler = 0;    
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
   TIM_ARRPreloadConfig(TIM2, ENABLE);

/* 设置更新请求源只在计数器上溢或下溢时产生中断 */    
     TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Global);     
     TIM_ClearFlag(TIM2, TIM_FLAG_Update);
}
/**  
  * @brief   us延时程序,10us为一个单位  
  * @param    
  *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us  
  * @retval  无  
  */
  
void Delay_us(__IO uint32_t nTime)
{     
/* 清零计数器并使能滴答定时器 */    
    TIM2->CNT   = 0;      
    TIM_Cmd(TIM2, ENABLE);     

for( ; nTime > 0 ; nTime--)    
     {
/* 等待一个延时单位的结束 */
while(TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != SET);     
     TIM_ClearFlag(TIM2, TIM_FLAG_Update);    
     }
    
    TIM_Cmd(TIM2, DISABLE);
}

在main函数中检验Delay_us的执行时间:

#include "stm32f10x.h"
#include "Timer_Drive.h"
#include "gpio.h"
#include "systick.h"

TimingVarTypeDef Time;

int main(void)
{        
   TIM2_Init();        
   SysTick_Init();    
   SysTick_Time_Init(&Time);

for(;;)    
    {        
        SysTick_Time_Start();         
        Delay_us(1000);        
        SysTick_Time_Stop();    
    }     
}

怎么去看检测结果呢?用调试的办法,打开调试界面后,将Time变量添加到Watch一栏中。然后全速运行程序,既可以看到Time中保存变量的变化情况,其中TimeWidthAvrage就是最终的结果。

7.png

可以看到TimeWidthAvrage的值等于0x119B8,十进制数对应72120,滴答定时器的一个滴答为1/72M(s),所以Delay_us(1000)的执行时间就是72120*1/72M (s) = 0.001001s,也就是1ms。验证成功。

备注:定时器方法输出检测结果有待改善,你可以把得到的TimeWidthAvrage转换成时间(以us、ms、s)为单位,然后通过串口打印出来,不过这部分工作对于经常使用调试的人员来说也可有可无。相关推荐:学习STM32单片机,绕不开的串口。

两种方法对比

软件测试方法

操作起来复杂,由于在原代码基础上增加了测试代码,可能会影响到原代码的工作,测试可靠性相对较低。由于使用32位的变量保存systick的计数次数,计时的最大长度可以达到2^32/72M = 59.65 s。

示波器方法

操作简单,在原代码基础上几乎没有增加代码,测试可靠性很高。由于示波器的显示能力有限,超过1s以上的程序段,计时效果不是很理想。但是,通常的单片机程序实时性要求很高,一般不会出现程序段时间超过秒级的情况。

直接转载来源:STM32嵌入式开发

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 30

一、SD卡概述

1、定义

SD卡(安全数码卡),是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(外语缩写PDA)和多媒体播放器等。

2、容量等级

1.png

3、SD卡框图

2.png

引脚说明:

3.jpg

4、SD卡与TF卡的区别

TF卡又名micro SD卡,个头是比SD卡的1/4还小,可以通过“TF转SD卡套”转换成SD卡。

二、 SD卡内部结构

(摘自SanDisk Secure Digital Card Product Manual Version 1.9)

1、 SD卡内部结构简图

4.png

由SD卡控制器和存储阵列组成,SD卡与外界的通讯接口是SD Bus或者SPI Bus。

2、 存储阵列结构图

5.png

Block:      

读写时的单元(数据传输单元),它的单位是“字节”。

Sector:     

如果CSD寄存器ERASE_BLK_EN = 0时,Sector是最小的擦除单元,它的单位是“块”。Sector的值等于CSD寄存器中的SECTOR_SIZE的值+1。

WP Group:   

最小的写保护单元,它的单位是“扇区”。

3、Buffer

6.png

SD Card的Buffer最大容量定义在CSD寄存器的READ_BL_LEN和WRITE_BL_LEN。它们的值是一样的,而且有可能超过512字节,尽管这样Block还是要设置成512字节,因为512字节是数据边界(这句话不是太理解)。也就是SD卡上有数据传输缓冲器Buffer,不同的产品可能不一样,但是在使用时要将Buffer设置成512字节。

参考资料:  

The card buffer size is described as maximum block length in the Card Specif ic Data (CSD) register for memory cards (for cards compliant with the Physical Layer Specification, READ_BL_LEN and WRITE_BL_LEN shall be the same) and in the Card Information Structure (CIS) for SDIO cards. Physical Layer Specification re-defines that maximum block length is only used to calculate capacity of memory card. Even though it indi cates larger than 512 bytes, block length shall be set to 512 byte for data transfer. This is because 512 bytes block l ength is required to keep compatibility with 512 bytes data boundary.

(摘自《Simplified_SD_Host_Controller_Spec.pdf》)

4、“存储阵列Block”--最小的存储单元

资料上的Block通通指的是数据传输时的最小单元,定义这个数值是为了数据传输、CRC校验等。

存储阵列通常采用NandFlash的结构,显然不能按字节存取,而这里讨论的“存储阵列Block”就是指这个概念。可惜的是目前,我还没有找到资料讨论这个问题,所以这一章节是笔者自己的推测。

据我推测存储阵列Block应该是512Byes,因为众多的数据都围绕着512Bytes在转。比如说最小的擦除单元是512Byes,最小的读写单位应该被设置成512Bytes,那么有理由推测是这个数值。

5、SD卡特殊功能寄存器

  • CID:  宽度128位,卡标识号

  • RCA:  宽度16位,卡相对地址,在初始化的时候确定

  • CSD:  宽度128位,卡描述数据:卡操作条件的信息

  • SCR:  宽度64位,SD卡配置寄存器:SD卡特定信息数据

  • OCR:  宽度32位,操作条件寄存

三、SDIO接口

7.png

四、SD卡协议之数据读、写、擦除

1、SD卡写数据块 

执行写数据块命令(CMD24-27) 时,主机把一个或多个数据块从主机传送到卡中,同时在每个数据块的末尾传送一个CRC码。主机传送数据,SD卡接收数据并将数据保存在Buffer中,累计接收数据达到Block长度的时候,SD卡把接下来的数据当做CRC校验码,并且开始数据校验。如果CRC校验错误,卡通过SDIO_D 线指示错误,传送的数据被丢弃而不被写入,所有后续(在多块写模式下)传送的数据块将被忽略。

如果主机传送部分数据而累计的数据长度未与数据块对齐,当不允许块错位( 未设置CSD的参数WRITE_BLK_MISALIGN),卡将在第一个错位的块之前检测到块错位错误( 设置状态寄存器中的ADDRESS_ERROR 错误位) 。当主机试图写一个写保护区域时,写操作也会被中止,此时卡会设置WP_VIOLATION位。 

数据块Block的最大长度定义在CSD中的WRITE_BL_LEN,但是在数据传输时应该用CMD16指令将其设置为512Byets,不去在意WRITE_BL_LEN是1024或者2048Bytes。

另外需要注意的是,Block的长度设置还要参考CSD寄存器的WRITE_BL_PARTIAL。当WRITE_BL_PARTIAL为0时,那么么办法Block只能设置为512Bytes;如果WRITE_BL_PARTIAL=1,那么允许将Block设置成更小的块,比如说一个字节。协议是这样规定的,但是据我分析如果这样的话SD卡的制作会非常复杂(写入的单位可以是字节),价格也会很高。笔者测试了自己的SD卡,WRITE_BL_PARTIAL 等于0,也就是不支持“块部分写”功能。 

2、SD卡读数据块

在读数据块模式下,数据传输的基本单元是数据块Block。为保证数据传输的正确,传输一个数据块Blcok后都有一个CRC校验码。笔者认为主机在累计接收到Block长度数据后,软件可以把接下来的数据当做CRC校验码,并且进行校验。

Block的最大值在CSD中(READ_BL_LEN) 给出了定义,但是在数据传输时应该用CMD16指令将其设置为512Byets,不去在意READ_BL_LEN是1024或者2048Bytes。

如果CSD寄存器中的READ_BL_PARTIAL等于1,可以传送的较小数据块,较小数据块是指开始和结束地址完全包含在一个物理块中。事实上,协议规定READ_BL_PARTIAL永远等于1,也就说在任何SD卡上都允许“读部分块”,读的块的最小字节是1Bytes。使用这种功能,可以通过CMD16命令设置更小的Block(比如说等于128)。读取的这128字节必须在512Bytes边界内,不能跨越边界(其实因为存储阵列是以512Bytes为单位的,读取“部分块”只能在一个块内,不允许跨块读)。

3、擦除SD卡

CSD寄存器ERASE_BLK_EN决定了SD卡的最小擦除单位。

当ERASE_BLK_EN等于0的时候,主机擦除的最小单位是扇区。比如一个Sector包含32个Block,擦除时的起始地址是5,而结束地址是40,那么实际擦除的块是从0到63。

8.png

当ERASE_BLK_EN等于1的时候,主机擦除的最小单位是512 Byetes。比如擦除时的起始地址是5,而结束地址是40,那么实际擦除的块就是从5到40。

9.png

五、SD卡物理层协议

SD卡的协议相对于SPI、I2C等协议的存储器来说相对复杂,包含SD卡物理层(机械封装、管脚、芯片结构、命令集等)、SD卡接口(SDIO)、SD主机控制器,甚至是软件设计的流程,都进行了详细的规定。

1、接口

① SDIO接口

参考《Simplified_SDIO_Card_Spec.pdf》

10.png

<1> CLK 时钟同步线

<2> CMD 命令信号线,主机发出的命令以及从机对命令的响应都是通过这条线进行传输

<3> DAT[3:0] 表示4条数据线,主机和从机的数据都是从这四条数据线上传输

② SPI接口

11.png

2、命令格式

12.png

3、响应格式

以R1为例

13.png

4、SD卡的工作状态

14.jpg

 

5、SD卡的两种状态信息

① Card Status

执行命令过程中的状态信息,比如地址不对齐错误、块长度错误、卡锁、ECC校验错误等等

blog.csdn.net/g_salamander

② SD Status

SD卡的专有特征,编程中不经常涉及。这个状态值有512位,不是通过命令线传送给主机,而是通过数据线。

六、STM32与SD卡相配的外设--SDIO适配器

 1、SDIO adapter 结构图

15.png

2、命令状态机(CPSM)

当发送命令和接收响应时,启动CPSM状态机。

16.png

3、数据通道状态机

当传输数据时,启动数据通道状态机。

17.png

4、FIFO

数据FIFO(先进先出)子单元是一个具有发送和接收单元的数据缓冲区。

FIFO包含一个每字32位宽、共32个字的数据缓冲区,和发送与接收电路。因为数据FIFO工作在AHB 时钟区域(HCLK/2),所有与SDIO时钟区域(SDIOCLK)连接的信号都进行了重新同步。依据TXACT和RXACT标志,可以关闭FIFO、使能发送或使能接收。TXACT和RXACT 由数据通道子单元设置而且是互斥的:

─ 当 TXACT 有效时,发送 FIFO 代表发送电路和数据缓冲区

─ 当 RXACT 有效时,接收 FIFO 代表接收电路和数据缓冲区

5、SDIO的特殊功能寄存器

  • SDIO电源控制寄存器(SDIO_POWER)

  • SDIO时钟控制寄存器(SDIO_CLKCR) : 时钟选择、分频

  • SDIO参数寄存器(SDIO_ARG)

  • SDIO命令寄存器(SDIO_CMD):控制发送命令

  • SDIO命令响应寄存器(SDIO_RESPCMD):包含响应命令中的命令索引

  • SDIO响应1..4寄存器(SDIO_RESPx):包含响应命令中的卡状态信息

  • SDIO数据定时器寄存器(SDIO_DTIMER)

  • SDIO数据长度寄存器(SDIO_DLEN):读或者写的长度,通常是是512的倍数

  • SDIO数据控制寄存器(SDIO_DCTRL):控制数据的读写方向、使能传输等信息

  • SDIO数据计数器寄存器(SDIO_DCOUNT):当DPSM状态机从Idle state切换到Wait_R或者Wait_S状态时,SDIO_LEN的数值加载到该寄存器中

  • SDIO状态寄存器(SDIO_STA)

  • SDIO清除中断寄存器(SDIO_ICR)

  • SDIO中断屏蔽寄存器(SDIO_MASK)

  • SDIO FIFO计数器寄存器(SDIO_FIFOCNT):当SDIO_DCTRL中的DTEN使能,并且DPSM处于Idle state时,SDIO_LEN/4的数值加载到该寄存器中

  • SDIO数据FIFO寄存器(SDIO_FIFO):读写数据缓冲FIFO

七、SD卡编程

SD卡的编程在STM32官方固件库中就有例程,而且野火开发板对该例程进行了中文注释,不必再把源码贴入。这里着重讲一下SD卡编程流程,主要包含SD卡初始化、SD卡读、SD卡写、SD卡擦除。

1、SD卡编程的内容

SD卡主要就是用来存储数据的,所以核心就是读写。为了实现这个目标,必须实现响应的驱动。

配置过程中,不仅要设置好SD控制器,还需要将SD卡设置到合适的状态。在读取状态的时候,不仅涉及到SD控制器的状态,还涉及到SD卡的状态。

2、SD卡初始化

① STM32外设SDIO初始化

端口配置、端口时钟、SDIO时钟、DMA2时钟使能

SDIO寄存器复位

设置时钟SDIO_CK为400KHz以下,设置数据线宽度,开启时钟、开启SDIO电源

② SD卡上电初始化

18.png

上电初始化流程如上图所示,笔者认为官方库提供的例程没有完全按照这个流程图的指示去做。事实上,官方库的程序只做了如上图红色方框内的流程,之外的没涉及。

CMD0命令复位所有的卡。

SD协议规定:在初始化的时候,使用ACMD41之前,必须先使用CMD8命令。而且ACMD41命令属于应用命令,在使用之前需要先发送命令CMD55。

CMD8命令是为了核查电源是否匹配。ACMD41命令不断询问SD卡是否支持主机提供的电压,并且询问SD卡是否上电完成进入准备状态。ACMD41命令还能询问SD卡的类型(SDSC、SDHC)。

③卡进一步核查、获取卡信息

发送命令CMD2,以获取CID信息。

发送命令CMD3,以获取RCA相对地址,可以通过多次发送CMD3获取不同的RCA值,但是只有最后一次的才是有效的RCA地址。

发送命令CMD9,以获取CSD寄存器。

④ 设置SDIO工作在数据传输模式

设置SDIO的时钟为24MHz、数据线宽度为4位。

通过SD_GetCardInfo函数将之前得到CID、CSD处理成卡的信息。

通过CMD7命令选择匹配地址的卡,而取消选择其他的卡。

至此,初始化完成。

3、读SD卡的一个块

  • 数据控制寄存器(SDIO_DCTRL)清零

  • 发送命令CMD16,设置SD卡的Block大小

  • 调用函数SDIO_DataConfig设置SDIO数据传输方式

  • 发送命令CMD17,读单个块

  • SDIO数据传输结束中断使能

  • SDIO的DMA传输功能使能

  • DMA设置,并使能

4、写SD卡的一个块 

  • 数据控制寄存器(SDIO_DCTRL)清零

  • 发送命令CMD16,设置SD卡的Block大小

  • 发送命令CMD24,写单个块

  • 调用函数SDIO_DataConfig设置SDIO数据传输方式

  • SDIO数据传输结束中断使能

  • DMA设置,并使能

  • 使能SDIO的DMA传输功能 

八、SD卡疑惑

1、SD卡擦除后,其中的内容是0,还是1 ? 

The data at the card after an erase operation is either '0' or '1', depends on the card vendor.The SCR register bit DATA_STAT_AFTER_ERASE (bit 55) defines whether it is '0' or '1'.(摘自《SD Specifications_Part_1_Physical_Layer_Specification_Ver3.00_Final_090416.pdf》)

也就是说这是芯片厂商生产工艺决定的,可以通过SCR寄存器的 DATA_STAT_AFTER_ERASE位得知。

2、在SDIO_DCTRL中设置传输Block的要求

Block大小决定了主机在发送数据时,发送到什么程度时开始发送CRC校验码;而在接收数据时,在接收到什么程度时开始把SD卡的数据作为CRC校验码并进行校验。Block还可能影响着其他的时序。在STM32的SDIO寄存器组中,SDIO_DCTRL中的位段DBLOCKSIZE决定主机Block大小。

在摘自《Simplified_SD_Host_Controller_Spec.pdf》的引文中,提到这样的配置要求:主机的Block一定要与SD卡设置的Block一样大小,这显然是必要的。我们经常设置SD卡的Block大小是512Bytes,所以设置DBLOCKSIZE为9(2^9 = 512)。

3、STM32固件库“stm32_eval_sdio_sd.c version v4.5.0”偶遇BUG

参考网页:http://www.cprogramdevelop.com/3742318/

4、SD卡写Block是怎样进行的?

写SD卡的单位是Block(512Bytes),再写之前要先整块擦除,然后才能写。

在多块写操作中,可以在发送多块写命令CMD25之前,有选择性的先发送命令ACMD23设置预擦除。怎样理解呢?

既然是有选择性的,也可以不发送ACMD23命令。在多块写的过程中,由于SD卡事先不知道你要写入几个块(CMD25命令只告诉SD卡要写入的起始地址),所以写入的过程是:根据需要判断要写一个块时,先擦除然后再写,再判断是否要写入下一个块,如果是就再擦除再写。

倘若发送ACMD23命令就不一样了,ADM23命令会在写命令CMD25生效之前,告诉SD卡准备写入的块数N。这样当CMD25命令生效的时候,SD卡会一次性先将这N个块都擦除,然后再一个块一个块写。由于擦除操作比较集中,所以整个多块写操作更节省时间。

九、SD卡参数测试

使用野火开发板配套例程做测试,笔者测试用的SD卡是金士顿的2G内存块,打印SD卡的参数信息如下:

Card Type is :1
ManufacturerID is :2

Card device size is :3795
Card Block Size is :1024
Card device size multiplier is :7
Card Capacity is :1990197248

the maximum read date block length is :1024
partial blocks for write allowed is :0
the maximum write date block length is :1024
erase single block enable is :1
erase sector size is :127
write protect group size is :0
RCA is :4660

Card Type:1         SDSC卡版本2.0

Card device size:  C_SIZE(CSD),为3795

Card Block Size:  max read data block length(READ_BL_LEN(CSD)) ,为1024 Bytes

Card device size multiplier is:  C_SIZE_MULT(CSD),为7

Card Capacity:  1990197248 Bytes

计算方法(摘自《Simplified_Physical_Layer_Spec.pdf》):

memory capacity = BLOCKNR * BLOCK_LEN 
  BLOCKNR = (C_SIZE+1) * MULT  (C_SIZE <= 4096)
  MULT = 2^(C_SIZE_MULT+2)        (C_SIZE_MULT < 8)
  BLOCK_LEN = 2^READ_BL_LEN,    (READ_BL_LEN < 12)

注意:SDSC最大为2GB。

the maximum read date block length:READ_BL_LEN(CSD) ,为1024 Bytes

partial blocks for write allowed:WRITE_BL_PARTIAL(CSD),为不支持

the maximum write date block length:WRITE_BL_LEN(CSD) ,为1024 Bytes

erase single block enable:ERASE_BLK_EN(CSD),为1,支持单块擦除

erase sector size:SECTOR_SIZE(CSD),实际扇区擦除的block数为(SECTOR_SIZE+1),为128 Blocks

write protect group size:WP_GRP_SIZE(CSD),实际保护的扇区数为(WP_GRP_SIZE+1),为1 Sector

RCA: SD卡相对地址为4660 

参考资料:《Simplified_SDIO_Card_Spec.pdf》

     《Simplified_Physical_Layer_Spec.pdf》

       《Simplified_SD_Host_Controller_Spec.pdf》

     《STM32芯片手册》

来源:STM32嵌入式开发

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 21

意法半导体TouchGFX软件包最新版本进一步简化在STM32 微控制器上开发美观的用户界面 (UI)。4.21 版增加了TouchGFX Stock功能,在网址https://fonts.google.com/icons提供大量的免费的图案、图像、图标。这个功能可帮助用户轻松管理图形资产,确保产品原型和最终产品用户界面的统一性和美观性。

1.jpg

4.21 版还增加了对 SVG 图像(可缩放矢量图形图像格式)的支持,这为开发酷炫的 UI 提供了更多自由空间。用户获取SVG图像需要用 TouchGFX Designer工具中新增的一个小部件,为确保高性能,SVG图像需用到意法半导体 STM32 MCU中的专用图形处理硬件,例如,NeoChrom GPU 处理器

此外,4.21版的TouchGFX Designer工具在导航、一般用途等方面进行50 多项改进,帮助开发人员更快、更高效地实现想法。

结合 STM32 开发生态系统的强大实力,包括软件工具、MCU 专用中间件和评估板,TouchGFX 帮助设计人员快速轻松地启动和推进项目。该软件包提供了为家用电器、楼宇自动化控制、工业机械、健身追踪器和其他可穿戴设备、医疗设备等产品创建引人注目的用户界面所需的一切。

现在,从www.st.com下载X-CUBE-TOUCHGFX 软件包,即可免费使用TouchGFX 4.21 版。

若想了解有关 TouchGFX 和 4.21 版的更多信息,请阅读 ST博客 :https://blog.st.com/touchgfx

关于意法半导体

意法半导体拥有48,000名半导体技术的创造者和创新者,掌握半导体供应链和先进的制造设备。作为一家半导体垂直整合制造商(IDM),意法半导体与二十多万家客户、成千上万名合作伙伴一起研发产品和解决方案,共同构建生态系统,帮助他们更好地应对各种挑战和新机遇,满足世界对可持续发展的更高需求。意法半导体的技术让人们的出行更智能,电力和能源管理更高效,物联网和互联技术应用更广泛。意法半导体承诺将于2027年实现碳中和。详情请浏览意法半导体公司网站:www.st.com

围观 7

意法半导体最新的 X-CUBE-TCPP软件包增强了公司的 USB Type-C® 端口保护芯片产品组合和STM32 接口IP(知识产权),简化USB Power Delivery产品研发。

111111111111111-min.jpg

USB Power Delivery技术规范支持从传统的 5V/0.5A一直到最新版本 3.1 规范中的 48V/5A(240 瓦)的工作模式。功率增容可以激发产品设计创新,有助于新的可持续发展法律出台,例如,最近欧盟批准USB Type-C 成为所有手机、平板电脑和相机的通用充电端口,以减少电子垃圾。利用 USB Power Delivery 的新产品设计包括移动电源、智能扬声器、PC 外围设备、通信设备、医疗设备、POS 终端、工业显示器和电池供电的嵌入式应用。

意法半导体的X-CUBE-TCPP软件包可以简化在STM32Cube 生态系统中的开发工作,并为意法半导体产品组合中的三个 USB Type-C 端口保护 IC提供软件库。这三款芯片是受电端TCPP01-M12、供电端TCPP02-M18 和双重角色电源 (DRP)TCPP03-M20。

TCPP01-M12TCPP02-M18TCPP03-M20可与意法半导体的STM32G0、STM32G4、STM32L5 和 STM32U5 微控制器 (MCU)的UCPD(USB Type-C和Power Delivery)接口IP配合使用,在标准功率范围内解决 USB 供电问题,最高功率可达 20V-5A(100 W)。把USB Type-C分成微控制器和端口保护芯片两部分可以用双片解决方案,以节省成本,降低开发复杂性,最大限度地减少 PCB 空间。STM32芯片还可用作主MCU。

Additionally, X-CUBE-TCPP assists development on STM32 MCUs that do not contain the Power Delivery PHY, to streamline compliance with the USB Type-C specification.

此外,X-CUBE-TCPP 还有助于在没有 Power Delivery PHY的 STM32 MCU 上开发应用,简化产品的USB Type-C规范合规设计。

用户使用X-CUBE-TCPP 软件库,配合X-NUCLEO-SNK1M1扩展板,选用NUCLEO-G071RBNUCLEO-G474RENUCLEO-L412RB-P任何一款搭载STM32 MCU的STM32 Nucleo-64开发板执行代码,可以加快受电应用开发。

开发供电端应用,X-CUBE-TCPP软件库可与X-NUCLEO-SRC1M1扩展板和任何一款无 Power Delivery的STM32 Nucleo-64 USB Type-C供电端开发板配合使用,或者与有Power Delivery 的NUCLEO-G071RB 或 NUCLEO-G474RE USB Type-C供电开发板配合。

开发有 Power Delivery 的 DRP应用,软件库需要与X-NUCLEO-DRP1M1扩展板和NUCLEO-G071RB 或 NUCLEO-G474RE主板配合使用。

这三块板子已通过 USB Implementers Forum 认证,并具有一个代表符合 USB-C Power Delivery规范的测试ID编号(TID),这确保开发人员开发的产品与现场的其他认证产品互操作。这些板子的 TID测试编号分别是 X-NUCLEO-SNK1M1 (TID 5205), X-NUCLEO-SRC1M1 (TID 7884)和 X-NUCLEO-DRP1M1(TID 6408)。

X-CUBE-TCPP软件包可从 www.st.com 或 GitHub 免费下载。

围观 14

1、前言

本应用笔记介绍如何管理 STM32 产品中的内存保护单元(MPU)。MPU 是用于存储器保护的可选组件。STM32 微控制器(MCU)中嵌入 MPU 之后变得更稳健可靠。在使用 MPU 之前,必须对其进行编程并加以启用。如果 MPU 没有启用,则存储系统的行为不会变化。

2、概述

MPU 可以使嵌入式系统更加稳健和安全:• 禁止用户应用程序破坏关键任务(例如操作系统核心)使用的数据• 将 SRAM 存储区域定义为非可执行(禁止执行 XN),以防止代码注入攻击• 修改存储访问属性MPU可最多保护16个内存区域。在 Armv6、Armv7 架构(Cortex-M0+、M3、M4、M7)下,这些区域可以依次拥有 8 个子区域(前提是区域至少有 256 字节))。

在 STM32 中,受保护区域的确切数量可能因内核和器件而有所不同,请参阅 Cortex-M33 MPU 寄存器获取详细信息。子区域的大小都是相等的,可以根据子区域号进行启用或禁用。因为最小区域大小是由缓存行长度(32 字节)驱动的,所以 8 个 32 字节的子区域对应一个 256 字节的区域。区域的编号为 0 至 15。

此外,还有一处默认区域,其 id 为-1。所有编号 0-15 的存储区域的优先级高于默认区域。这些区域可以重叠,也可以嵌套。区域 0-15 的优先级由低到高,这也决定了区域重叠的方式。优先级是固定的,不可更改。在 Armv8 架构(Cortex-M33)中,使用起始地址和终止地址来定义区域,使开发人员能够以灵活、简单的方式组织这些区域。

此外,正是区域大小的可灵活配置得到提升,故Cortex-M33就没有子区域的概念了。下图显示的示例包含六个区域。该示例显示区域 4 与区域 0 和 1 重叠。区域 5 完全包含在区域 3 内。因为优先级是递增的,所以重叠区域(橙色)优先。因此,如果区域 0 是可写的,而区域 4 不可写,那么位于区域 0 和区域 4 重叠部分的地址为不可写。

1.png

Conclusion:

在 Armv8 架构(Cortex-M33)中,现在不允许区域重叠。由于 MPU 区域的定义更加灵活,因此没有必要重叠MPU 区域。 

MPU 是统一的,意味着没有单独的区域用于数据和指令。

MPU 还可以用于定义其他存储器属性(如可缓存性),可以导出到系统级缓存单元或存储存控制器。Arm 架构中的存储器属性设置可以支持两种级别的缓存:内部缓存和外部缓存。STM32F7 和 STM32H7 系列仅支持一种级别的缓存(L1-缓存)。 

缓存控制由缓存控制寄存器实现全局控制,但 MPU 可以指定缓存策略以及区域是否可缓存。

2.1存储器模型 

在 STM32 产品中,处理器具有固定的默认存储器映射,可提供最多 4 Gb 的可寻址存储器。

2.png

3.png

3、  Cortex-M0+/M3/M4/M7 

存储器类型、寄存器和属性

存储器映射和 MPU 编程将存储器映射分为多个区域。每个区域都有已定义的存储器类型和存储器属性。存储器类型和属性决定该区域的访问行为。

3.1 存储器类型

有三种常见的存储器类型: 

• 普通存储器:允许 CPU 以有效方式安排字节、半字和字的加载和存储(编译器不了解存储器区域类型)。对于普通存储器区域,CPU 不一定按照程序中列出的顺序执行加载/存储操作。 

• 器件存储器:在器件区域内,负载和存储是严格按照顺序进行的。这是为了确保以正确的顺序设置寄存器。 

• 强排序存储器:所有操作始终按以编程方式列出的顺序执行,CPU 会等待加载/存储指令执行(有效的总线访问)结束,然后执行程序流中的下一条指令。这可能导致性能损失。

3.2 存储器属性

区域的属性与大小寄存器(MPU_RASR)是设置所有存储器属性的地方。该表显示了 MPU_RASR 寄存器中对于区域的属性和大小的简要描述。

4.png

前一个表格中的参数详情如下: 

• XN 标志位控制代码的执行。为了在区域内执行指令,特权级别必须有读访问权限,而 XN 必须为 0。否则,会产生 MemManage 报错。 

• 数据访问权限(AP)字段定义存储区域的 AP。

下表对访问权限进行了说明:

5.png

• S 字段面向可共享的存储区域:存储系统在一个有多个总线主控的系统(例如,一个处理器带一个 DMA 控制器)中提供总线主控之间的数据同步。强排序的存储器始终可共享。如果多个总线主控可以访问一个不可共享的存储区域,软件必须确保总线主控之间的数据一致性。STM32F7 系列和 STM32H7 系列不支持硬件一致性。S 字段相当于不可缓存的存储器。 

• TEX、C 和 B 位用于定义区域的缓存属性,以及(在某种程度上)可共享性。按下表对其进行编码。

在 STM32 微控制器中加入 MPU 使其稳健、可靠,而且在某些情况下更安全 - 防止应用程序任务访问或破坏其他任务使用的堆栈和数据存储器。该应用笔记描述了不同的存储器属性、类型和 MPU 寄存器。其中还提供了 MPU(使用 STM32Cube HAL)设置示例,以说明如何配置 STM32 MCU 中的 MPU。如需详细了解 MPU 寄存器,请参阅 Cortex 内核编程手册。本应用笔记内容较长,篇幅有限仅展示部分,完整内容请点击“阅读原文”下载原文档。

来源:STM32单片机

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 14

1.问题原因

某客户测试 STM32H753xi 板子上的 ECC 功能,用于监控 AXI-SRAM 区域,但不是很明白 RAMECC FAR 寄存器在 RM0433 中的描述, “Bits 31:0 FADD[31:0]: ECC error failing address”。

比如在 AXI-SRAM 中,如果客户示例显示的是 FAR = 0x2004,但是这个地址值 0x2004 并不在 AXI-SRAM 范围之内,客户该如何理解 FAR 寄存器?希望能够有详尽的描述,这个 FAR 寄存器的偏移地址是 Word 地址还是 Byte 地址或其他?我们先来看看相关参考手册中关于 RAMECC 的介绍去寻找答案。

2.RAMECC 控制单元

RAM ECC 控制单元的数量取决于不同的 STM32H7 系列。比如,对于STM32H74x/5x 和 STM32H72x/3x 它们的每一个域都有一个 RAMECC 的控制器单元,为了描述简单,表述如下: 

Domain 1 (D1) RAMECC unit = RAMECC1Domain 2 (D2) RAMECC unit = RAMECC2Domain  3  (D3)   RAMECC  unit   =  RAMECC3

详细的说明请参考 RM0433 参考手册 rev7 中的截图:

1.jpg

3.RAMECC 寄存器地址

对于上图 Table 11 的 RAMECC 控制单元的地址总结成如下表格,具体的参考RM0433 的第二章节 Memory and bus architecture 中的 table 8.

2.jpg

4.RAMECC 寄存器

每一个 RAMECC 控制单元(RAMECC1、RAMECC2、RAMECC3)的监控单元Monitor number 均分别含有如下的一套寄存器组(其中 RAMECC_IER 为共同拥有)。 

接下来我们以 RAMECC1 为例进行分析,其边界地址为:0x52009000 -0x520093FF,那么对于该 RAMECC1 控制单元中的寄存器组,对于每一个寄存器:

3.jpg

以 RAMECC1 的起始地址 0x52009000 为基准:RAMECC_IER:中断使能,偏移地址 0x00,该寄存器地址即为:0x52009000。

RAMECC_MxCR:配置寄存器,偏移地址 0x20 *x,x 为 ECC 监控单元号,该寄存器地址的表达式为:0x52009000 + 0x20 * x ,x 取值范围= [1..5](见上面表格 Table 11 ECC controller mapping),所以: 

Monitor 1 - AXI SRAM ECC 监控单元,该寄存器地址即为 0x52009020,监控大小为整个 AXI SRAM 的 512KB 字节(0x24000000 -0x2407FFFF)。 

Monitor 2 - ITCM-RAM ECC 监控单元,该寄存器地址0x52009040, 监控大小为整个ITCM RAM的64KB字节(0x00000000 -0x0000FFFF)。  

Monitor 3、Monitor 4、Monitor 5 中该 RAMECC_MxCR 寄存器的地址,以此类推。

RAMECC_MxSR -- 状态寄存器,偏移地址: 0x24 + 0x20 * (x - 1),x 为 ECC monitor number 号码(见上面表格 Table 11 ECC controller mapping)。那么该寄存的地址为:0x52009000 + 0x24 + 0x20 * (x-1) ,x 取值范围 = [1..5]:

Monitor 1:0x52009024

Monitor 2:0x52009044

Monitor 3 : 0x52009064 

Monitor 4 : 0x52009084 

Monitor 5 : 0x520090a4 

RAMECC_MxFAR --失败地址寄存器,表达式:0x52009000 + 0x28 + 0x20 * (x-1) , x取值 = [1..5]: 

Monitor 1:0x52009028

Monitor 2:0x52009048

Monitor 3:0x52009068

Monitor 4:0x52009088

Monitor 5:0x520090a8

RAMECC_MxFDRL -- 失败数据低位,表达式 0x52009000 + 0x2c + 0x20 * (x-1) ,x 取值= [1..5] 

Monitor 1:0x5200902c

Monitor 2:0x5200904c

Monitor 3:0x5200906c

Monitor 4:0x5200908c

Monitor 5:0x520090ac

RAMECC_MxFDRH -- 失败数据高位,表达式 0x52009000 + 0x30 + 0x20 * (x-1),x 取值= [1..5] 

Monitor 1:0x52009030 

Monitor 2:0x52009050 

Monitor 3:0x52009070 

Monitor 4:0x52009090 

Monitor 5:0x520090b0 

RAMECC_MxFECR --失败 ECC 错误代码,表达式 0x52009000 + 0x34 + 0x20 * (x1) ,x 取值 = [1..5]

Monitor 1:0x52009034

Monitor 2:0x52009054

Monitor 3:0x52009074

Monitor 4:0x52009094

Monitor 5:0x520090b4

5.解决问题

通过查询资料与试验,FADD[31:0]中表述的地址是 word 而不是 bit。为了计算真实的地址,客户需要用如下公式计算:真实地址= 所处内存的首地址 + FADD x 字节数。 


现在举个例子,如上述提到的 FADD= 0x2004 : 

- 对于 64-bit word 的内存 :如 AXI RAM : 0x2400 0000 + 0x2004 * 8 = 0x2401 0020; 

- 对于 32-bit word 的内存 :如 SRAM1 : 0x3000 0000 + 0x2004 * 4=0x3000 8010 ;

来源: STM32单片机

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 17

页面

订阅 RSS - STM32