简单记录LPC1788学习过程的寄存器操作---SSP学习

寄存器的直接操作可以比较直观学习,深入了解芯片功能!


在学习过程中,发现一点容易被忽视而又很严重的问题---那就是关于SSP1的引脚使用P0[7]-P0[8]-P0[9]时,是W型IO配置。寄存器的第7位很容易被我们设置为0--但是手册上是要求必须为1,否则不能正常工作,这里我走了一点弯路。


#include"ssp_lpc1788.h"

#define SPI_FLASH_PageSize      256   //页大小
#define SPI_FLASH_PerWritePageSize      256   //写页大小

/*----------------初始化SSP0-------------*/
void SSP0_Init(unsigned long sysClk, unsigned spiClk)
{
    volatile uint32_t dummy;

dummy = dummy;

LPC_IOCON->P2_22 =0x22; // SSP0_SCK
    LPC_IOCON->P2_26 =0x22; // SSP0_MISO
    LPC_IOCON->P2_27 =0x22; // SSP0_MOSI

LPC_IOCON->P2_23=0x30; //SSP1_CS-直接普通上拉IO
    LPC_GPIO2->DIR |= (1UL << 23);   //输出
    LPC_GPIO2->SET|=(1<<23);//置一

LPC_SC->PCONP |= (1UL << 21);   //SSP0 时钟开启

LPC_SSP0->CR0  = 0x0007;   // 8Bit, CPOL=0, CPHA=0 
    LPC_SSP0->CR1  = 0x0002;   // SSP0-使能-主模式

LPC_SSP0->CPSR = sysClk/spiClk; //时钟预分频寄存器

while( LPC_SSP0->SR & ( 1 << 4 ) ); //忙

while( LPC_SSP0->SR & ( 1 << 2 ) )  //接收FIFO不为空
    {
        dummy = LPC_SSP0->DR; //假读取去清空FIFO
    }

}

/*-------------SSP0-发送数据-----------------*/
void SSP0_WriteByte(unsigned char data)  
{
    uint8_t Dummy;

LPC_SSP0->DR = data; //载入要发送的数据
    while (LPC_SSP0->SR & (1 << 4)){} //等待发送完成
    Dummy=LPC_SSP0->DR; //假读取去清空FIFO
}

/*-------------SSP0-接收数据-----------------*/
uint8_t SSP0_RegisterByte(void)  
{
    LPC_SSP0->DR = 0xFF; //无效指令
    while (LPC_SSP0->SR & (1 << 4)){} //忙等待

return (LPC_SSP0->DR); //接收数据
}


/*-----------------------------------SSP1--------------------------*/
/*----------------初始化SSP1-------------*/
void SSP1_Init(unsigned long sysClk, unsigned spiClk)
{
    volatile uint32_t dummy;


    LPC_IOCON->P0_7 =0xA2; // SSP1_SCK
    LPC_IOCON->P0_8 =0xA2; // SSP1_MISO
    LPC_IOCON->P0_9 =0xA2; // SSP1_MOSI

LPC_IOCON->P0_6=0x30; //SSP1_CS-普通上拉IO
    LPC_GPIO0->DIR |= (1UL << 6);   //输出
    LPC_GPIO0->SET|=(1<<6);//置一

LPC_SC->PCONP |= (1UL << 10);   //SSP1 时钟开启

LPC_SSP1->CR0  = 0x0007;   // 8Bit, CPOL=0, CPHA=0 
    LPC_SSP1->CR1  = 0x0002;   // SSP1-使能-主模式

LPC_SSP1->CPSR = sysClk/spiClk; //时钟预分频寄存器

while( LPC_SSP1->SR & ( 1 << 4 ) ); //忙

while( LPC_SSP1->SR & ( 1 << 2 ) )  //接收FIFO不为空
    {
        dummy = LPC_SSP1->DR; //假读取去清空FIFO
    }
}

/*-------------SSP1-发送数据-----------------*/
void SSP1_WriteByte(unsigned char data)   
{
    uint8_t Dummy;

LPC_SSP1->DR = data; //载入要发送的数据
    while (LPC_SSP1->SR & (1 << 4)){}  //等待发送完成
    Dummy=LPC_SSP1->DR; //假读取去清空FIFO
}

/*-------------SSP1-接收数据-----------------*/
uint8_t SSP1_RegisterByte(void)   
{
    LPC_SSP1->DR = 0xFF; //无效指令
    while (LPC_SSP1->SR & (1 << 4)){}  //忙等待

return (LPC_SSP1->DR); //接收数据
}

/*---------------------W25Q16---------------*/
//---------写使能---
void SSP_FLASH_WriteEnable(void)
{
    FLASH_CS_LOW();
    SSP0_WriteByte(0x06);
    FLASH_CS_HIGH();
}
//--------等待写完成--
void SSP_FLASH_WaitForWriteEnd(void)
{
    uint16_t i=2000;
    uint8_t FLASH_Status = 0;

    FLASH_CS_LOW();
    SSP0_WriteByte(0x05);
    do
    {
        FLASH_Status = SSP0_RegisterByte();
        i--; 
    }
    while (((FLASH_Status & 0x01) == 1)||(i==0)); 
    FLASH_CS_HIGH();

}

/*----关于擦除---在写入数据之前必须保证被写入的位值是0xff---这就是擦除的作用*/

//-------------扇区擦除----------
void SSP_FLASH_SectorErase(uint32_t SectorAddr)
{
    SSP_FLASH_WriteEnable();//写使能
    SSP_FLASH_WaitForWriteEnd();//忙状态

    FLASH_CS_LOW();//CS=0
    SSP0_WriteByte(0x20);//0x20
    SSP0_WriteByte((SectorAddr & 0xFF0000) >> 16);//擦除扇区起始地址
    SSP0_WriteByte((SectorAddr & 0xFF00) >> 8);
    SSP0_WriteByte(SectorAddr & 0xFF);
    FLASH_CS_HIGH();//CS=1

    SSP_FLASH_WaitForWriteEnd();//忙状态--等待擦除完成
}
//-----------块擦除-------
void SSP_FLASH_BlockErase(uint32_t BlockAddr)
{
    BlockAddr*=65536;//0x010000
    SSP_FLASH_WriteEnable();//写使能
    SSP_FLASH_WaitForWriteEnd();

    FLASH_CS_LOW();
    SSP0_WriteByte(0xD8);//0xD8
    SSP0_WriteByte((BlockAddr & 0xFF0000) >> 16);//擦除块起始地址
    SSP0_WriteByte((BlockAddr & 0xFF00) >> 8);
    SSP0_WriteByte(BlockAddr & 0xFF);
    FLASH_CS_HIGH();

    SSP_FLASH_WaitForWriteEnd();
}
//----------整片擦除--
void SSP_FLASH_BulkErase(void)
{
    SSP_FLASH_WriteEnable(); //写使能

    FLASH_CS_LOW();
    SSP0_WriteByte(0xc7);  //整片擦除
    FLASH_CS_HIGH();

    SSP_FLASH_WaitForWriteEnd();
}
//---------单页写入-----
void SSP_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    SSP_FLASH_WriteEnable();

    FLASH_CS_LOW();
    SSP0_WriteByte(0x02);//CMD2--0x02--------页写入
    SSP0_WriteByte((WriteAddr & 0xFF0000) >> 16);//写入起始地址
    SSP0_WriteByte((WriteAddr & 0xFF00) >> 8);
    SSP0_WriteByte(WriteAddr & 0xFF);

    if(NumByteToWrite > SSP_FLASH_PerWritePageSize) //写入数据多余页最大数据
        NumByteToWrite = SSP_FLASH_PerWritePageSize;
    while (NumByteToWrite--)
    {
        SSP0_WriteByte(*pBuffer);  //写数据
        pBuffer++;
    }
    FLASH_CS_HIGH();

    SSP_FLASH_WaitForWriteEnd();
}
//--------多页写入---
void SSP_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;

    Addr = WriteAddr % SSP_FLASH_PageSize; //首页地址
    count = SSP_FLASH_PageSize - Addr;//首页要写入的数据个数
    NumOfPage =  NumByteToWrite / SSP_FLASH_PageSize;//页数
    NumOfSingle = NumByteToWrite % SSP_FLASH_PageSize; //余数--最后一页不满一页个数

    if (Addr == 0) 
    {
        if (NumOfPage == 0) //只有一页
        {
            SSP_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite); //Ö±½ÓдÈë
        }
        else //多页
        {
            while (NumOfPage--) //写满页的数据
            {
                SSP_FLASH_PageWrite(pBuffer, WriteAddr, SSP_FLASH_PageSize);
                WriteAddr +=  SSP_FLASH_PageSize;
                pBuffer += SSP_FLASH_PageSize;
            }

            SSP_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);//写最后不满一页的数据
        }
    }
    else 
    {
        if (NumOfPage == 0) 
        {
            if (NumOfSingle > count) 
            {
                temp = NumOfSingle - count;
                SSP_FLASH_PageWrite(pBuffer, WriteAddr, count);
                WriteAddr +=  count;
                pBuffer += count;

            SSP_FLASH_PageWrite(pBuffer, WriteAddr, temp);
            }
            else
            {
                SSP_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
            }
        }
        else 
        {
            NumByteToWrite -= count;
            NumOfPage =  NumByteToWrite / SSP_FLASH_PageSize;
            NumOfSingle = NumByteToWrite % SSP_FLASH_PageSize;

            SSP_FLASH_PageWrite(pBuffer, WriteAddr, count);
            WriteAddr +=  count;
            pBuffer += count;

            while (NumOfPage--)
            {
                SSP_FLASH_PageWrite(pBuffer, WriteAddr, SSP_FLASH_PageSize);
                WriteAddr +=  SSP_FLASH_PageSize;
                pBuffer += SSP_FLASH_PageSize;
            }

            if (NumOfSingle != 0)
            {
                SSP_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
            }
        }
    }
}
//--------读数据-----------
void SSP_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    FLASH_CS_LOW();
    SSP0_WriteByte(0x03);  //CMD3--0x03-----//读数据
    SSP0_WriteByte((ReadAddr & 0xFF0000) >> 16);
    SSP0_WriteByte((ReadAddr& 0xFF00) >> 8);
    SSP0_WriteByte(ReadAddr & 0xFF);

    while (NumByteToRead--) 
    {
        *pBuffer = SSP0_RegisterByte();//读入到指定数组
        pBuffer++;
    }
    FLASH_CS_HIGH();
}

/*-----------读取厂家ID------------*/
uint32_t SSP_FLASH_ReadID(void)
{
    uint32_t temp1=0,temp2=0,temp3=0,temp=0;

LPC_GPIO0->CLR|=(1<<6); //CS=0

SSP1_WriteByte(0x9F);           //读取ID指令
    temp1 =SSP1_RegisterByte();    //厂家编号
    temp2 =SSP1_RegisterByte();//存储类型
    temp3 =SSP1_RegisterByte();//容量

temp =(temp1<<16)|(temp2<<8)|(temp3);

LPC_GPIO0->SET|=(1<<6);//CS=1;

return temp;

}


LPC1788--SSP设置驱动W25Q16--以及特别注意点相关推荐

  1. STM8L151 使用硬件SPI驱动W25Q16 Flash

    SPI:有四根线的串行通信协议,允许与其他设备以半.全双工.同步.串行方式通信. MISO:主模式输入.从模式输出线 MOSI:主模式输出.从模式输入线 CLK:时钟线 NSS:从设备选择引脚,主设备 ...

  2. visual studio下设置驱动开发环境

    原文地址:visual studio 下设置驱动开发环境 作者:空空的左手 摘自:http://hi.baidu.com/%D0%DD%CF%D0e%D7%E5/blog/item/ad97a10e5 ...

  3. 模拟SPI驱动W25Q16程序 (DSP 28X系列)

    为了驱动SPI FLASH而写的驱动程序,写的时候主要是板子的自带SPI接口被占用,只好使用IO口模拟一个SPI接口程序: w25q16 芯片工作在SPI工作模式0和模式3中:在此spi的原理不多做说 ...

  4. 基于FPGA的密码锁开发——(3)密码设置模块驱动

    *在第一篇密码锁驱动开发完之后,就可以构思密码设置驱动了 需求如下: 1.要准确输入6位密码,输入位数不足就判定密码设置失败 2.只有在解锁状态下可以进行密码修改 3.在密码设置完成后要通知到密码锁模 ...

  5. (五)打印机驱动设置—没有开不了的钱箱

    有很多用户在使用打印机时,由于不会设置驱动导致出现很多问题,下面几篇文章就专门讲如何设置打印机驱动. 现在大部分的票据打印机都会有钱箱接口方便客户使用收银系统,很多用户在使用时,安装完驱动,然后打印测 ...

  6. 关于AD绘制驱动板如何设置电气间距

    对于走高电压和大电流的驱动板在进行PCB布线时.首先需确认哪些是高压线,哪些是低压线,哪些是小信号线,以及哪些是过大电流的驱动线.合理设置PCB网络的线宽以满足驱动线的过电流能力,合理设置PCB网络中 ...

  7. android 虚拟键盘改变单个按键颜色_这款机械键盘很特别!一亿次按键寿命还有高颜值...

    电脑主机要上RGB,那外设自然不能落下,虽说没有60%性能加成,用炫酷的灯光点亮桌面的感觉也是不错的.德国老牌外设品牌--冰豹(ROCCAT)2018年发布了Vulcan系列机械键盘,凭借着独特的设计 ...

  8. pve虚拟机导入gho_迁移WIN10和VMW虚拟机到ProXmoX VE(二):PVE设置和迁移windows

    迁移WIN10和VMW虚拟机到ProXmoX VE(二):PVE设置和迁移windows 2020-03-27 13:54:06 23点赞 162收藏 18评论 首先,这个和原先win平台目的是一样的 ...

  9. omap3530 linux串口驱动,omap3530(Cortex-A8)硬件平台软件调试笔记

    内容简介:描述调试过程中所遇问题及其解决办法和过程,可作为新手的FAQ使用. 1. Issue: 不能从SD卡启动. Fixed: 自己疏忽造成,手册已经提到要先用"HP Disk Stor ...

最新文章

  1. Mysql4种方式避免重复插入数据!
  2. 人形AI捉迷藏惊煞网友:飞檐走壁纯靠自学,表情丰富还会合作,姚班学霸吴翼参与...
  3. linux替换包的脚本,Andorid 自动替换logo打包脚本(支持windows和linux)
  4. [数据库] Navicat for Oracle基本用法图文介绍
  5. TopN算法与排行榜
  6. python git切换分支_git命令之切换分支
  7. python数据分析实战案例logistic_Python机器学习随笔之logistic回归识别手写数字
  8. pytorch4:简单的线性回归
  9. div不继承父类样式_Java三大特性之继承
  10. 计算机资格考试中级工程师种类,中级工程师职称考试类别及注意事项
  11. 常用的HTTP头部字段的基本含义(转)
  12. 计算机教育工作,计算机教育教学工作总结
  13. 数学知识点回顾(二)
  14. SpringBoot 的配置文件
  15. 清楚理解const_cast类型转换
  16. PDF转图片的所有可行方法,全部都在这里了!
  17. php源码查后门,某一次排查源码后门的过程
  18. Ubuntu下VScode代码字体设置——monospace(等宽字体)
  19. 压缩或解压文件出现循环冗余检查的解决办法
  20. jy-09-SERVLETJSP——Servlet-Cookie-Session

热门文章

  1. python学习笔记-day5-文件修改
  2. 分布式爬虫系统设计、实现与实战
  3. 超声换能器的主要性能指标
  4. VMware虚拟机连不上移动硬盘或USB
  5. 【百度人脸识别】》人脸对比接口的调用
  6. matlab逆变器原理,三相SPWM逆变器的调制建模和仿真详解
  7. 联想服务器系统初始化失败怎么回事,登陆进程初始化失败原因及解决办法
  8. 世界500强面试题----数学能力
  9. 纪念我的第一个Python程序:猜数字
  10. 【最新程序设计赛】2022 GDE全球开发者大赛 #华为云 #¥1,290,000 #09.30开始