S5PV210开发系列五_sd卡驱动实现

2023-11-07

S5PV210开发系列五

sd卡驱动实现

象棋小子    1048272975

SD卡(Secure Digital Memory Card)具有体积小、容量大、数据传输快、可插拔、安全性好等优点,被广泛应用于便携式设备上。例如作为数码相机的存储卡,作为手机、平板多媒体扩展卡用的TF卡(micro sd)。笔者此处就S5PV210的 sd卡驱动实现作一个简单的介绍。

1. sd卡概述

sd卡技术是在MMC卡的基础上发展起来的,其尺寸与MMC卡一样,只是比MMC卡厚了0.7mm,因此sd设备可以识别并存取MMC卡。sd卡接口除了保留MMC卡的7针外,还在两边加了2针,作为数据线,目的是通过把传输方式由串行变成并行,以提高传输速率。此时的规范为sd1.0版本,最高容量只能到4GB。为了跟进产品的更新换代,sd联合协会在06年发布了容量更大、存储更快的下一代sd卡规范sd2.0。该规范重新定义了sd卡的速度等级,分为三档:Class 2、4、6,分别对应写入速度2MB/s、4MB/s、6MB/s。根据卡容量又分为标准卡(小于2GB)和高容量卡(2GB~32GB),目前市面上应用的sd卡绝大部分都是sd2.0版本的卡。为了让储存卡更加迷你,通过sd卡规范标准,又衍生了MiniSD卡和Micro SD卡,这些卡均比标准sd卡尺寸小,通过sd转接卡可以当作一般的sd卡使用。尤其是Micro SD卡,可以算是最小的存储卡了,超小的体积可以极大的节省消费电子产品内部设计的空间,基本目前的android手机均是选用Micro SD卡作为多媒体扩展储存卡。随着科技的进步,sd2.0规范sd卡也渐渐无法满足应用的需求,在10年sd联合协会又发布了新的sd3.0规范,该规范定义了sdxc和uhs,并增加了Class10,容量范围为32GB~2TB。在sdxc卡仍需进一步坐等其价格下降的情况下,sd4.0规范已经开始在紧张的制订中,这已超出本文的讨论范围内了。

2. sd卡驱动编写

sd卡共支持三种传输模式:spi模式、1位sd模式、4位sd模式。所有的sd卡都必须支持较老的spi/mmc模式,这个模式支持慢速的四线spi接口,使很多微控制器都可以通过spi或模拟spi接口来读写sd卡。由于S5PV210具有sd卡主机控制器,并且支持sd2.0标准,此处只分析4位sd模式、sd2.0及sd1.0版本的sd卡驱动实现,sd2.0以上版本sd卡、MMC卡、spi方式读写sd卡在本文不适用。

sd2.0标准定义了物理层相关规范以及主机控制器规范,sd卡驱动的编写必须参考这两个规范,主要是对S5PV210中的sd主机控制器的编程,这部分对所有具有sd主机控制器的微处理器均是适用的,只是寄存器名称的差异。此处只根据sd2.0规范讲解几个重要的过程或概念,这些过程具体的实现请参考sd驱动模块中相应的函数实现。

2.1. sd卡初始化及识别过程

sd卡上电后,将进入idle状态,此时的sd卡为1位sd模式。通过拉低CS线将可使sd进入spi模式(不再讨论范围内),在sd模式下卡的初始化及识别过程见图2.1.1,其步骤如下:

1) 发送CMD0软件复位所有的卡到idle状态。

2) 发送CMD8来检查卡是否支持主机电压(2.7v~3.3v),这个命令在sd2.0以上才被定义,若没有收到回复信号,则可能为sd1.0或MMC卡,若接收到卡回复信号,说明为sd2.0版本卡,跳转到步骤5

3) CMD8没有收到回复信号,可进一步发送ACMD41(CMD55+CMD41),参数HCS位为0(非高容量卡),如果没有回复信号,说明是MMC卡或其它不能识别的卡,可进一步发送CMD1确定是否MMC卡(此处不再分析)

4) ACMD41能收到回复,并且从回复中确定sd卡己准备好,即可确定这是sd1.x版本的卡,若回复中表明sd卡未准备好,则需重复发送ACMD41等待卡准备好,可通过超时(卡一直busy)判断卡不支持主机电压,此时表明卡不可用。判断出sd1.x的卡后,跳转到步骤9

5) CMD8有回复说明为sd2.0以上的卡,从回复中确定卡是否能在该电压下工作,不能则认为卡不可用。

6) 回复中确定卡能在2.7v~3.3v电压工作后,进一步发送ACMD41(CMD55+CMD41),参数HCS位为1表明主机支持高容量的卡

7) 检查ACMD41卡回复中忙标志,若卡处于忙状态,则重复发送ACDM41,直到卡准备好,可通过超时(卡一直忙状态)可认为该卡不可用。

8) ACMD41回复准备好后,再检查回复中的CCS位,该位为1说明是sd2.0高容量sdhc卡,若为0,则说明为sd2.0标准容量卡。

9) 在识别出sd1.x、sd2.0标准卡或sd2.0高容量卡后,此时卡进入ready态。进一步通过CMD2请求卡发送其CID(Card Identification),此时卡进入Identification态。

10) 卡在Identification态后,发送CMD3请求卡发布一个16位新的相对地址(RCA),以后主机与卡之间的点对点通信均会以这个RCA地址来进行,此时卡进入Stand-by态。

11) 至此,卡的初始化及识别过程结束,此时卡进入数据传输模式(data transfer mode)

图2.1.1. sd卡初始化及识别流程

2.2. 数据传输模式

sd卡是一个非常典型的状态机,每个状态只会响应该个状态下的特定命令,不要尝试在某个状态下发送这个状态不支持的命令,sd卡不会对该命令进行响应,命令只会超时。应该通过特定的触发条件转变状态或等待状态迁移完成后,再发送对应状态的命令。如图2.2.1,要想写一个块的数据到sd卡,在stand-by态的情况下,必须通过CMD7选择卡,让卡进入transfer态,然后再发送CMD24单块写命令,再发送一块的数据,此时卡进入Programming态,这时如果又紧接发送CMD24进行单块写将不会成功,必须等待sd卡编程完,从Programming态返回到transfer态才能再次接收下一个块写命令。同样,在transfer态想通过CMD9来获得Card-Specific Data(CSD),必须通过CMD7取消选择卡,此时卡进入stand-by态后,即可通过CMD9来获得卡信息。

图2.2.1. sd卡数据传输模式

2.3. 主机控制器对卡的初始化

sd卡主机控制器都可以根据sd2.0规范给出的卡初始化及识别流程进行卡的初始化,主机控制器寄存器的设置主要有以下几点,具体的实现可参考Hsmmc_Init()这个初始化函数。

1) 设置功能引脚,把相应引脚配置成sd接口用引脚

2) 设置sd卡时钟在100k~400k,sd卡在识别阶段必须用慢速时钟进行访问

3) 按照规范给出的卡初始化流程对卡进行发送相应的命令并处理回复,成功后卡进入stand-by态

4) 通过发送CMD7选择卡,使卡进入transfer态,因为卡的大部分操作如读、写、擦除等均是在这个状态下来进行的,此时卡已完全准备好接收读写命令了。

5) 设置sd卡的时钟到一个较高值,sd卡默认支持最高25M时钟,对于sd1.1以上标准,可以检查卡是否支持高速模式,若支持则切换到高速模式,最高支持50M,频率越高,数据传输速率越快

6) 通过ACMD6(CMD55+CMD6)来设置sd模式的位宽为4,sd卡初始化后默认是1线宽,更多的数据线将有更大的带宽,数据传输速率最高12.5MB/s(25M、4线)或25MB/s(50M、4线)。

7) 发送CMD16设置块长度,对于标准卡,可通过CMD16来设置块命令(如块读、块写)所操作块的长度(以字节数计),可实现字节的读写,但对于高容量卡这个命令将被忽略,高容量卡一个块的长度均是固定512字节的。通常通过CMD16设置块长度为512字节。至此卡初始化完成。

int Hsmmc_Init(void)

{

int32_t Timeout;

uint32_t Capacity;

uint32_t i;

uint32_t OCR;

uint32_t Temp;

uint8_t SwitchStatus[64];

SD_SCR SCR;

uint8_t CSD[16];

uint32_t c_size, c_size_multi, read_bl_len;

 

// 设置HSMMC的接口引脚配置

#if (HSMMC_NUM == 0)

// channel 0,GPG0[0:6] = CLK, CMD, CDn, DAT[0:3]

GPG0CON_REG = 0x2222222;

// pull up enable

GPG0PUD_REG = 0x2aaa;

GPG0DRV_REG = 0x3fff;

// channel 0 clock src = SCLKEPLL = 96M

CLK_SRC4_REG = (CLK_SRC4_REG & (~(0xf<<0)))| (0x7<<0);

// channel 0 clock = SCLKEPLL/2 = 48M

CLK_DIV4_REG = (CLK_DIV4_REG & (~(0xf<<0)))| (0x1<<0);

   

#elif (HSMMC_NUM == 1)

// channel 1,GPG1[0:6] = CLK, CMD, CDn, DAT[0:3]

GPG1CON_REG = 0x2222222;

// pull up enable

GPG1PUD_REG = 0x2aaa;

GPG1DRV_REG = 0x3fff;

// channel 1 clock src = SCLKEPLL = 96M

CLK_SRC4_REG = (CLK_SRC4_REG & (~(0xf<<4)))| (0x7<<4);

// channel 1 clock = SCLKEPLL/2 = 48M

CLK_DIV4_REG = (CLK_DIV4_REG & (~(0xf<<4)))| (0x1<<4);

   

#elif (HSMMC_NUM == 2)

// channel 2,GPG2[0:6] = CLK, CMD, CDn, DAT[0:3]

GPG2CON_REG = 0x2222222;

// pull up enable

GPG2PUD_REG = 0x2aaa;

GPG2DRV_REG = 0x3fff;

// channel 2 clock src = SCLKEPLL = 96M

CLK_SRC4_REG = (CLK_SRC4_REG & (~(0xf<<8)))| (0x7<<8);

// channel 2 clock = SCLKEPLL/2 = 48M

CLK_DIV4_REG = (CLK_DIV4_REG & (~(0xf<<8)))| (0x1<<8);

   

#elif (HSMMC_NUM == 3)

// channel 3,GPG3[0:6] = CLK, CMD, CDn, DAT[0:3]

GPG3CON_REG = 0x2222222;

// pull up enable

GPG3PUD_REG = 0x2aaa;

GPG3DRV_REG = 0x3fff;

// channel 3 clock src = SCLKEPLL = 96M

CLK_SRC4_REG = (CLK_SRC4_REG & (~(0xf<<12)))| (0x7<<12);

// channel 3 clock = SCLKEPLL/2 = 48M

CLK_DIV4_REG = (CLK_DIV4_REG & (~(0xf<<12)))| (0x1<<12);  

   

#endif

// software reset for all

__REGb(HSMMC_BASE+SWRST_OFFSET) = 0x1;

Timeout = 1000; // Wait max 10 ms

while (__REGb(HSMMC_BASE+SWRST_OFFSET) &(1<<0)) {

    if (Timeout== 0) {

        return-1; // reset timeout

    }

    Timeout--;

    Delay_us(10);

}  

   

Hsmmc_SetClock(400000); // 400k

__REGb(HSMMC_BASE+TIMEOUTCON_OFFSET) = 0xe; // 最大超时时间

__REGb(HSMMC_BASE+HOSTCTL_OFFSET) &= ~(1<<2);// 正常速度模式

// 清除正常中断状态标志

__REGw(HSMMC_BASE+NORINTSTS_OFFSET) =__REGw(HSMMC_BASE+NORINTSTS_OFFSET);

// 清除错误中断状态标志

__REGw(HSMMC_BASE+ERRINTSTS_OFFSET) =__REGw(HSMMC_BASE+ERRINTSTS_OFFSET);

__REGw(HSMMC_BASE+NORINTSTSEN_OFFSET) = 0x7fff; //[14:0]中断状态使能

__REGw(HSMMC_BASE+ERRINTSTSEN_OFFSET) = 0x3ff; //[9:0]错误中断状态使能

__REGw(HSMMC_BASE+NORINTSIGEN_OFFSET) = 0x7fff; //[14:0]中断信号使能  

__REGw(HSMMC_BASE+ERRINTSIGEN_OFFSET) = 0x3ff; //[9:0]错误中断信号使能

   

Hsmmc_IssueCommand(CMD0, 0, 0, CMD_RESP_NONE); // 复位所有卡到空闲状态 

       

CardType = UNUSABLE; // 卡类型初始化不可用

// 没有回复,MMC/sd v1.x/notcard

if (Hsmmc_IssueCommand(CMD8, 0x1aa, 0, CMD_RESP_R7)) {

    for (i=0;i<100; i++) {

    Hsmmc_IssueCommand(CMD55,0, 0, CMD_RESP_R1);

// CMD41有回复说明为sd卡

    if(!Hsmmc_IssueCommand(CMD41, 0, 0, CMD_RESP_R3)) {

// 获得回复的OCR(操作条件寄存器)值

        OCR = __REG(HSMMC_BASE+RSPREG0_OFFSET);

// 卡上电是否完成上电流程,是否busy

        if (OCR& 0x80000000) {

            CardType= SD_V1; // 正确识别出sd v1.x卡

            Debug("SDcard version 1.x is detected\r\n");

            break;

        }

    } else {

        // MMC卡识别

        Debug("MMCcard is not supported\r\n");

        return-1;

    }

    Delay_us(1000);            

    }

} else { // sd v2.0

    Temp =__REG(HSMMC_BASE+RSPREG0_OFFSET);

// 判断卡是否支持2.7~3.3v电压

    if(((Temp&0xff) == 0xaa) && (((Temp>>8)&0xf) == 0x1)) {

    OCR = 0;

    for (i=0;i<100; i++) {

        OCR |=(1<<30);

        Hsmmc_IssueCommand(CMD55,0, 0, CMD_RESP_R1);

        Hsmmc_IssueCommand(CMD41,OCR, 0, CMD_RESP_R3); // reday态

        OCR =__REG(HSMMC_BASE+RSPREG0_OFFSET);

// 卡上电是否完成上电流程,是否busy

        if (OCR& 0x80000000) {

// 判断卡为标准卡还是高容量卡

        if (OCR& (1<<30)) {

            CardType= SD_HC; // 高容量卡

            Debug("SDHCcard is detected\r\n");

        } else {

            CardType= SD_V2; // 标准卡

            Debug("SDversion 2.0 standard card is detected\r\n");

        }

        break;

        }

        Delay_us(1000);

    }

}

}

if (CardType == SD_HC || CardType == SD_V1 || CardType== SD_V2) {

// 请求卡发送CID(卡ID寄存器)号,进入ident

    Hsmmc_IssueCommand(CMD2,0, 0, CMD_RESP_R2);

// 请求卡发布新的RCA(卡相对地址),Stand-by状态

    Hsmmc_IssueCommand(CMD3,0, 0, CMD_RESP_R6);

// 从卡回复中得到卡相对地址

    RCA =(__REG(HSMMC_BASE+RSPREG0_OFFSET) >> 16) & 0xffff;

// 选择已标记的卡,transfer状态

    Hsmmc_IssueCommand(CMD7,RCA<<16, 0, CMD_RESP_R1);

    Hsmmc_Get_SCR(&SCR);

    if(SCR.SD_SPEC == 0) { // sd 1.0 - sd 1.01

// Version 1.0 doesn't support switching

        Hsmmc_SetClock(24000000);// 设置SDCLK = 48M/2 = 24M           

    } else { //sd 1.10 / sd 2.0

    Temp = 0;

    for (i=0;i<4; i++) {

// switch check

    if(Hsmmc_Switch(0, 0, 1, SwitchStatus) == 0) {

// Group 1, function 1 high-speed bit 273

        if(!(SwitchStatus[34] & (1<<1))) {

        // Thehigh-speed function is ready

// Group, function 1 high-speed support bit 401

        if(SwitchStatus[50] & (1<<1)) {

        //high-speed is supported

        if(Hsmmc_Switch(1, 0, 1, SwitchStatus) == 0) { // switch

// function switch in group 1 is ok?

            if ((SwitchStatus[47]& 0xf) == 1) {

// result of the switch high-speed in function group 1

            Debug("Switchto high speed mode: CLK @ 50M\r\n");

            Hsmmc_SetClock(48000000);// 设置SDCLK = 48M   

            Temp= 1;

            }

        }

        }

        break;

        }

    }

    }

    if (Temp ==0) {

        Hsmmc_SetClock(24000000);// 设置SDCLK = 48M/2 = 24M

    }

    }

 

    if (!Hsmmc_SetBusWidth(4)){

        Debug("Setbus width error\r\n");

        return-1; // 位宽设置出错

    }

// 此时卡应在transfer态

    if(Hsmmc_GetCardState() == CARD_TRAN) {

// 设置块长度为512字节

    if(!Hsmmc_IssueCommand(CMD16, 512, 0, CMD_RESP_R1)) {

        __REGw(HSMMC_BASE+NORINTSTS_OFFSET)= 0xffff; // 清除中断标志

        Hsmmc_Get_CSD(CSD);

// CSD v1.0->sd V1.x, sd v2.00 standard

        if((CSD[15]>>6) == 0) {

        read_bl_len= CSD[10] & 0xf; // [83:80]

        c_size_multi= ((CSD[6] & 0x3) << 1) + ((CSD[5] & 0x80) >> 7);

        c_size =((int32_t)(CSD[9]&0x3) << 10) + ((int32_t)CSD[8]<<2)

                + (CSD[7]>>6); // [73:62]

        Capacity= (c_size + 1) << ((c_size_multi + 2) +

(read_bl_len-9)); // block(512 byte)

        } else {

        c_size =((CSD[8]&0x3f) << 16) + (CSD[7]<<8) + CSD[6];

// 卡容量为字节(c_size+1)*512Kbyte,以1扇区512 byte字,卡的扇区数为

        Capacity= (c_size+1) << 10;// block (512 byte)

        }

        Debug("CardInitialization succeed\r\n");  

        Debug("Capacity:%ldMB\r\n", Capacity / (1024*1024 / 512));

        return 0;// 初始化成功                        

    }

    }

}

Debug("Card Initialization failed\r\n");

return -1; // 卡工作异常

}

 

2.4. 主机命令的发送

sd规范对命令包格式、回复包、数据的传输方式等均作了详细的要求。虽然sd卡主机控制器可以帮我们对命令进行打包,对回复进行解包,产生CRC,并在sd总线上输出相应的时序。我们仍需要告诉sd卡主机控制器需发送的命令、这个命令的参数、这个命令发送后是否需要使用data线, sd卡的回复类型。这些设置通过主机控制器CMDREG寄存器来实现。主要有以下几点,具体的实现可参考Hsmmc_IssueCommand()这个命令发送函数。

1) 命令发送时,需检查命令线是否已被使用,若是,则等待正在发送的命令发送完才能发送这个命令

2) 如果命令回复会带忙信号(如R1b回复),则需检查数据线是否已被使用,若是,则等待数据线空闲,带忙回复命令发送后,sd卡会拉低DAT[0]线表明sd卡正忙,数据线不可用。

3) 把命令参数写入ARGUMENT这个寄存器中

4) 在CMDREG中设置命令值[13:8]

5) 设置是否需使用data线,如块读、块写等命令发送后,会紧接着在data线上传输数据,其它不需传输数据的命令不要设置使用data线CMDREG[5]

6) 设置sd卡的回复类型,绝大部分命令在sd卡正确响应后,都会对主机进行回复(R1-R7,R1b),每个命令对应的回复类型请参考sd卡规范。回复类型长度可能为136或48,回复中是否包含CRC或命令值的反馈,如果包含,则告诉主控制器检查回复中相应的CRC或命令值反馈是否正确,以确定传输正确。CMDREG设置好后,主控制器就会发送命令并接收设定长度的回复并根据设定检查CRC、命令值反馈是否正确(若回复中包含CRC或命令值反馈的话)

7) 等待命令完成,检查中断状态位NORINTSTS[15]以确定命令是否有错误,若没有错误并且检测到NORINTSTS[0]命令完成位为1,则说明命令发送成功。其它情况说明命令未能成功发送。

 

2.5. 驱动模块接口

通常对于一个sd卡驱动模块,至少实现卡初始化、块读、块写这三个接口函数。这通常是一个文件系统最基本的底层磁盘接口实现。具体可参考Hsmmc_Init()、Hsmmc_ReadBlock()和Hsmmc_WriteBlock()这三个函数的实现。

3. 附录

Hsmmc.rar,包含sd卡驱动模块实现Hsmmc.c/Hsmmc.h。

http://pan.baidu.com/s/1nsJx0

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

S5PV210开发系列五_sd卡驱动实现 的相关文章

  • STM32裸机开发(3) — 使用汇编点亮LED灯

    STM32裸机开发 xff08 3 xff09 使用汇编点亮LED灯 一 启动流程 对于STM32F103从flash的启动流程如下 xff1a 首先设置栈 xff1a CPU会从0x08000000读取值 xff0c 用来设置SP 不使用
  • IAR软件应用中的错误提示

    1 Q xff1a Error e16 Segment XDATA Z size 0x19a1 align 0 is too long for segment definition At least 0xe4c more bytes nee
  • GD32F205在IAR上移植FreeRTOS

    目录 简述 xff1a 第一步 xff1a 准备最简工程与系统第二步 xff1a 拷贝源码第三步 xff1a 编译器IAR配置第四步 xff1a 工程代码修改第五步 xff1a 编译工程 简述 xff1a 1 主芯片 xff1a GD32F
  • IAR教程之IAR安装

    IAR安装 1 下载 1 1打开官网 1 2找到要下载的版本 1 3下载 同学们除了可以下载最新版本尝鲜之外 xff0c 还可以下载之前的版本 低版本IAR打开高版本IAR工程 xff0c 工程配置会错乱 xff0c 导致编译报错问题 xf
  • IAR for ARM 无法烧写

    一直用的IDE都是Keil xff0c 最近需要用到的一款芯片只有IAR这一种环境可以从Demo里直接用 xff0c 所以用到了IAR xff0c 但发现自己装好了IAR xff08 版本8 32 1 xff09 并破解后 xff0c 编绎
  • s5pv210时钟系统详解

    S5PV210时钟系统 1 什么是时钟系统 xff1f 时钟系统的作用 xff1f 时钟系统指的由固有频率来控制的系统 作用 xff1a 有了一定的频率 xff0c 工作才能有序 xff0c 有节奏的进行着 2 S5PV210的时钟系统是怎
  • IAR下载报错 “Fatal error: Failed to connect to CPU Session aborted!”

    当IAR下载程序进入单片机运行时出现这个弹窗之后就再也下载不进去程序了 xff0c 报以下错误 解决办法 xff1a 这时候就需要对单片机进行复位了 xff0c 一般是先看电路有没有复位按键如果没有复位按键则需要找到复位电路然后找到电路中的
  • IAR下载算法制作

    IAR下载算法制作 作者 Lucas 时间 2020 12 06 17 06 18 摘要 本文档主要介绍如何在IAR环境下制作QSPI下载算法 本文使用到的硬件 软件如下 编译器 xff1a IAR 8 32 单片机 xff1a STM32
  • IAR新建工程

    下载库函数 本文介绍基于 IAR 43 官方标准固件库 xff0c 来新建 STM8S003F 工程 xff0c STM8S 的标准固件库可以到 ST 的官方网站中找到并下载 xff1a ST官网 1 在搜索栏上搜索 STM8S003F x
  • ARM 之七 主流编译器(armcc、iar、gcc for arm)详细介绍

    必备 在讲解各编译器之前 xff0c 必须先了解一下以下文件 这些文件在编译器目录下或者编译生成目标平台的可执行程序时经常见到 此外 xff0c 还需要注意区分 Windows 平台 和 Linux 平台的文件 o 文件 xff1a 指的是
  • IAR 中如何调用EmEditor

    IAR 中如何调用EmEditor 文本编辑器我一直都用EmEditor Emeditor是一款很优秀的纯文本编辑器 xff0c 它对中日韩等亚洲字符集支持的很好 xff0c 不仅有语法高亮显示功能 xff0c 搜索替换功能也是近乎可爱的强
  • iar如何生成hex文件

    生成方法如下 1 工具需求 1 iar平台 2 第一种方法 首先在工程选项options里面 选中output converter选项 接着勾中Generate additional output选项 1 然后在Output format
  • S5PV210开发系列五_sd卡驱动实现

    S5PV210开发系列五 sd卡驱动实现 象棋小子 1048272975 SD卡 Secure Digital Memory Card 具有体积小 容量大 数据传输快 可插拔 安全性好等优点 被广泛应用于便携式设备上 例如作为数码相机的存储
  • iar中 让代码在sram中运行

    环境 iar 8 40 1 MCU mk64 1 关键字 ramfunc iar中可以利用关键字 ramfunc将函数放在ram中 带 ramfunc的函数调用不带 ramfunc的函数会出现警告 同时cpu 执行速度会变慢 ramfunc
  • MSP432学习笔记:IAR的环境配置(官方demo程序的测试)

    近来入手一块MSP432 折腾了一天 终于把官方demo程序导入IAR 可以愉快的写代码了 以下是我个人的解决办法 首先 如果要使用IAR对TI的单片机进行开发 首先要下载对应的单片机型号的MSPWARE 本人目前使用的是TI的MSP432
  • Error[Pe147] in IAR

    系统 win10 IDE IAR MCU cc2530 Error Error Pe147 declaration is incompatible with banked func xdata reentrant void UartSend
  • Fatal Error[Cp001]: Copy protection check, No valid license found for this product [24]

    解决方法 1 卸载IAR 2 以管理员身份打开IAR安装包 3 以管理员身份打开IAR注册机 4 正常安装即可 5 安装完成后以管理员身份打开IAR 编译程序就会正常
  • 与(有符号)枚举值的按位运算

    我正在使用标志的枚举值 typedef enum a 0x00 b 0x01u the u has no influence as expected c 0x02u the u has no influence as expected en
  • ARM Data Abort错误异常调试

    所以现在我明白我遇到了 ARM 数据中止异常 我了解了如何捕获异常本身 STL 库中的错误地址 但我想在异常之前返回堆栈帧 我正在使用 IAR 工具链 它告诉我异常后调用堆栈不可用 有没有一种技巧可以说服工具向我显示调用堆栈 感谢您的快速帮
  • 如何停止优化器丢弃未使用的变量?

    我想调试我的代码 但无法访问进程中的内部层 因为这会干扰与硬件的通信 在监视列表会干扰基本读取访问的情况下执行易失性操作 因此 我正在测试接口的返回值 但 IAR 编译器甚至会优化未使用的易失性变量 和这样的声明 i object foo

随机推荐