打印
[其他ST产品]

HAL库关于SPI访问FLASH的学习心得,关键代码已贴出

[复制链接]
214|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cr315|  楼主 | 2023-3-9 13:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
直接上代码。
我再总结几点:
    1.HAL库自带的发送函数对NSS高低电平的管理不太好用,不管用软件还是硬件管理,都需要自己管理NSS引脚的电平。
    2.发送写或擦除命令前,都需要使能后才可以生效。
    3.擦除操作后需要等待,我测试写入数据不需要,马上读数据就有了。1个扇区需要等待两万一千多个循环周期。擦除数据,后面的地址不是开始,只要是指定扇区的地址即可。20H + 0~4095都是擦除第一个扇区。
    4.读取数据无太多限制,想从哪个地址,随便读多少个长度都可以。
    5.写入数据就要注意了,页写入从指定地址开始写,如果长度超出当前页了,HAL库没有帮你跳转下一页,会继续从当前页头开始写,反复循环直到写完指定长度的数据。
      所以我们写入的时候就要注意地址和页对齐。

欢迎交流,有疑问的也可以问我。

uint32_t waitCout = 0;
// 处理发送指令
static void FLASH_Send_CMD(uint8_t code,uint8_t*sendBuf,uint16_t sendSize,uint8_t*recvBuf,uint16_t recvSize)
{               
        // 擦除或写入指令处理前要先使能
        if(code == CMD_SectorErase || code == CMD_PageProgram){
                FLASH_Send_CMD(CMD_WriteEnable,sendBuf,1,recvBuf,0);
        }
      
        uint16_t i = 0;
      
        *sendBuf = code;
      
        # if 1
    printf("发送指令 : ");
    for(i=0; i<sendSize; i++) {
        printf("%02X ",sendBuf[i]);
    }
    printf("---end\n");
# endif
      
      
    SPI_FLASH_CS_LOW;      
        HAL_SPI_Transmit(&hspi1,sendBuf,sendSize,1000);
      
        if(recvSize>0){
                HAL_SPI_Receive(&hspi1,recvBuf,recvSize,1000);
                if(code == CMD_ReadStatusReg){
//                        printf("状态等待值为:%02XH\n",*recvBuf);
                        while((*recvBuf)&0x01){
                                waitCout++;
                                HAL_SPI_Receive(&hspi1,recvBuf,1,1000);
//                                printf("状态等待值为:%02XH\n",*recvBuf);
                        }
                        printf("等待次数:%d\n",waitCout);
                }
                              
# if 1
                printf("接收到数据 : ");
                for(i=0; i<recvSize; i++) {
                        printf("%02X ",recvBuf[i]);
                }
                printf("---end\n");
# endif               
        }
      
    SPI_FLASH_CS_HIGH;
      
               
        // 擦除或写入指令处理后要等待忙状态变空闲
//        if(code == CMD_SectorErase || code == CMD_PageProgram){        // 读寄存器状态,主要是看是否在处理数据,也就是BUSY位
        if(code == CMD_SectorErase){        // 测试多次,写入数据未出现BUSY不需要等待
                FLASH_Send_CMD(CMD_ReadStatusReg,sendBuf,1,recvBuf,1);
        }
}



void FLASH_SendRecv(uint8_t code,uint8_t*sendBuf,uint16_t sendSize,uint8_t*recvBuf,uint16_t recvSize)
{
//        printf("指令:%02X 长度:%d\n",code,sendSize);
        uint16_t i = 0,j = 0;
    uint8_t dummySize = 0;
    uint8_t addrSize = 0;
        if(code == CMD_Power_DeviceID) { // 电源唤醒和读取DeviceID功能
        dummySize = 3;
        sendSize = 1 + dummySize;
        recvSize = 1;
    } else if(code == CMD_JEDEC_ID) { // 读出数据与0XEF4017匹配,看看是否是成功启动Flash
        sendSize = 1 + dummySize;
        recvSize = 3;
    } else if(code == CMD_SectorErase) { // 擦除1个扇区
        addrSize = 3;
        sendSize = 1 + addrSize;
    } else if(code == CMD_PageProgram) { // 按页(256Byte)来写数据,超出的会循环覆盖
        addrSize = 3;
        sendSize += (1 + addrSize);
    } else if(code == CMD_ReadData) { // 读指定地址开始指定长度的数据 读数据无长度限制
        addrSize = 3;
        sendSize = 1 + addrSize;
    } else{
                        printf("未整理指令%02XH\n",code);
                        return;
        }           

        // sendBuf数据整理
    for(i = 0; i<dummySize; i++) {
        sendBuf[1+i] = CMD_Dummy;
    }

               
      
      
        // 如果地址不对齐或长度超出256Byte,写入到当前页最后,不会换页,会从当前页头接着写,多数据循环进行
        uint32_t dataSize = sendSize - 4; // 获取要写入的数据长度
        uint32_t addr = (sendBuf[1]<<16) + (sendBuf[2]<<8) + sendBuf[3];
        if((code == CMD_PageProgram) && (dataSize > SPI_FLASH_PageSize || dataSize + addr > SPI_FLASH_PageSize)){
                uint8_t firstSize = SPI_FLASH_PageSize - addr%SPI_FLASH_PageSize; // 发出的第一段长度
                printf("firstSize:%d\n",firstSize);
                if(firstSize > 0){
                        // 先把第一段多出的部分发出去
                        FLASH_Send_CMD(CMD_PageProgram,sendBuf,firstSize+4,recvBuf,0);
                }               
               
                // 剩下的如果不是正好满页,多出的部分要再发一次,剩下的地址对齐
                addr += firstSize;
                uint16_t cycle = (dataSize-firstSize)/SPI_FLASH_PageSize;        // 剩下分成几段发送
                if((dataSize-firstSize)%SPI_FLASH_PageSize != 0){
                        cycle++;
                }
                uint8_t pageWrite[SPI_FLASH_PageSize+4];        // 剩下的数据存储到pageWrite数据位一起发出去
                for(i=0;i<cycle;i++){
                        for(j=0;(j<SPI_FLASH_PageSize+4) && (j+i*SPI_FLASH_PageSize < sendSize - firstSize);j++){
                                if(j == 0){
                                        pageWrite[j] = sendBuf[j];
                                }else if(j == 1){
                                        pageWrite[j] = addr>>16&0xff;
                                }else if(j == 2){
                                        pageWrite[j] = addr>>8&0xff;
                                }else if(j == 3){
                                        pageWrite[j] = addr&0xff;
                                }else if(j >= 4){
                                        pageWrite[j] = sendBuf[j+i*SPI_FLASH_PageSize+firstSize];
                                }
                        }
                        addr += SPI_FLASH_PageSize;
                        FLASH_Send_CMD(CMD_PageProgram,pageWrite,j,recvBuf,0);
                }
        }else{
                // 一般发送指令 一次
                FLASH_Send_CMD(code,sendBuf,sendSize,recvBuf,recvSize);
        }
}

使用特权

评论回复
沙发
帛灿灿| | 2024-4-8 08:27 | 只看该作者

当电路出现异常过压并达到其击穿电压时

使用特权

评论回复
板凳
Bblythe| | 2024-4-8 09:30 | 只看该作者

例如下图中在SPI信号线上串联电阻就是为了改善匹配情况

使用特权

评论回复
地板
周半梅| | 2024-4-8 11:26 | 只看该作者

即原/副边交错通断。

使用特权

评论回复
5
Pulitzer| | 2024-4-8 12:29 | 只看该作者

般只要关注值、精度、额度功率

使用特权

评论回复
6
童雨竹| | 2024-4-8 14:25 | 只看该作者

然后将其用作在PCB组装过程中放置在另一个板上的独立部件。

使用特权

评论回复
7
Wordsworth| | 2024-4-8 15:28 | 只看该作者

ESD静电保护器基本上都是通过静电进行吸收和耗散

使用特权

评论回复
8
Clyde011| | 2024-4-8 16:31 | 只看该作者

这类型灌封胶一般分为A、B双组份在进行1:1的配比后再进行灌封的操作

使用特权

评论回复
9
公羊子丹| | 2024-4-8 17:24 | 只看该作者

然后在专用站中检查每个半孔,

使用特权

评论回复
10
万图| | 2024-4-8 18:27 | 只看该作者

同时把异常高压箝制在一个安全水平之内

使用特权

评论回复
11
Uriah| | 2024-4-8 19:30 | 只看该作者

从而抑制电路的振荡。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1327

主题

3834

帖子

0

粉丝