查看: 4501|回复: 6

【LPC845月饼板】+ W25Qxx SPIFLASH驱动起来,存数据就不怕了

[复制链接]
  • TA的每日心情
    擦汗
    15 分钟前
  • 签到天数: 2406 天

    连续签到: 115 天

    [LV.Master]伴坛终老

    84

    主题

    2万

    帖子

    3

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    22340
    最后登录
    2025-8-24
    发表于 2022-10-26 18:22:00 | 显示全部楼层 |阅读模式
        本来准备移植ARM2D图形的,例子还没准备好,下次再说。今天就说说如何驱动SPI flash吧。    LPC845月饼板上有一块spi flash,主要是为了存储一些资源数据等等。LPC845本身flash不够多,到时想做一些lcd显示图片字体的话,资源会不足。后面还会说说如何编写flash的下载算法。下载算法已经基本调好了,可以直接下载数据到flash上了。

        进入正题,下面说一下如何驱动spi flash。
    要驱动spiflash,首先看看原理图,找到IO管脚,然后初始化管脚,初始化SPI。电路图部分如下:
    1.jpg
    2.jpg

    这里要说明一下,LPC845只有2个SPI外设。lcd屏幕用了一个SPI0,上期WS2812灯用了一个SPI1.所以这个SPIFLASH只能和他们共用一个SPI外设了。我这里是WS2812和SPIFLASH共用SPI1在,分时复用。
    下面是spi初始化部分:
    1. void drv_spi_gpio_init(void)
    2. {
    3.     CLOCK_EnableClock(kCLOCK_Iocon);
    4.     CLOCK_EnableClock(kCLOCK_Gpio0);
    5.     CLOCK_EnableClock(kCLOCK_Gpio1);
    6.    
    7.     CLOCK_EnableClock(kCLOCK_Spi0);
    8.     CLOCK_EnableClock(kCLOCK_Spi1);
    9.    
    10.     CLOCK_Select(kSPI0_Clk_From_MainClk);
    11.     CLOCK_Select(kSPI1_Clk_From_MainClk);
    12.    
    13.     RESET_PeripheralReset(kSPI0_RST_N_SHIFT_RSTn);
    14.     RESET_PeripheralReset(kSPI1_RST_N_SHIFT_RSTn);

    15.     gpio_pin_config_t SPILCD_IN_config = {
    16.         .pinDirection = kGPIO_DigitalInput,
    17.         .outputLogic = 1U,
    18.     };
    19.     gpio_pin_config_t SPILCD_IOH_config = {
    20.         .pinDirection = kGPIO_DigitalOutput,
    21.         .outputLogic = 1U,
    22.     };
    23.     gpio_pin_config_t SPILCD_IOL_config = {
    24.         .pinDirection = kGPIO_DigitalOutput,
    25.         .outputLogic = 0U,
    26.     };
    27.     /* Initialize GPIO functionality on pin */
    28.     GPIO_PinInit(GPIO, 0, 7, &SPILCD_IOL_config);//LCD_BLK
    29.     GPIO_PinInit(GPIO, 1, 6, &SPILCD_IOH_config);//LCD_DC
    30.     GPIO_PinInit(GPIO, 1, 7, &SPILCD_IOH_config);//LCD_RST
    31.     GPIO_PinInit(GPIO, 1,18, &SPILCD_IOH_config);//LCD_CS
    32.     GPIO_PinInit(GPIO, 1,19, &SPILCD_IOH_config);//LCD_CLK
    33.     GPIO_PinInit(GPIO, 0, 6, &SPILCD_IOH_config);//LCD_MOSI
    34.    
    35.     GPIO_PinInit(GPIO, 1,13, &SPILCD_IOH_config);//RGB_MOSI
    36.    
    37.     GPIO_PinInit(GPIO, 1,8, &SPILCD_IOH_config); //FLASH_CS
    38.     GPIO_PinInit(GPIO, 1,9, &SPILCD_IN_config); //FLASH_MISO
    39.     GPIO_PinInit(GPIO, 0,12, &SPILCD_IOH_config);//FLASH_CLK
    40.     GPIO_PinInit(GPIO, 0,13, &SPILCD_IOH_config);//FLASH_MOSI
    41.    
    42.     const uint32_t spilcd_ioc = (/* Selects pull-up function */
    43.                               IOCON_PIO_MODE_PULLUP |
    44.                               /* Enable hysteresis */
    45.                               IOCON_PIO_HYS_EN |
    46.                               /* Input not invert */
    47.                               IOCON_PIO_INV_DI |
    48.                               /* Disables Open-drain function */
    49.                               IOCON_PIO_OD_DI |
    50.                               /* Bypass input filter */
    51.                               IOCON_PIO_SMODE_BYPASS |
    52.                               /* IOCONCLKDIV0 */
    53.                               IOCON_PIO_CLKDIV0);
    54.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_7,  spilcd_ioc);
    55.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_6,  spilcd_ioc);
    56.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_7,  spilcd_ioc);
    57.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_18, spilcd_ioc);   
    58.    
    59.     /* Enables clock for switch matrix.: enable */
    60.     const uint32_t SPI_LCD_CLK = (/* Selects pull-up function */
    61.                                     IOCON_PIO_MODE_PULLUP |
    62.                                     /* Enable hysteresis */
    63.                                     IOCON_PIO_HYS_EN |
    64.                                     /* Input not invert */
    65.                                     IOCON_PIO_INV_DI |
    66.                                     /* Disables Open-drain function */
    67.                                     IOCON_PIO_OD_DI |
    68.                                     /* Bypass input filter */
    69.                                     IOCON_PIO_SMODE_BYPASS |
    70.                                     /* IOCONCLKDIV0 */
    71.                                     IOCON_PIO_CLKDIV0);
    72.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_19, SPI_LCD_CLK);

    73.     const uint32_t SPI_LCD_MOSI = (/* Selects pull-up function */
    74.                                     IOCON_PIO_MODE_PULLUP |
    75.                                     /* Enable hysteresis */
    76.                                     IOCON_PIO_HYS_EN |
    77.                                     /* Input not invert */
    78.                                     IOCON_PIO_INV_DI |
    79.                                     /* Disables Open-drain function */
    80.                                     IOCON_PIO_OD_DI |
    81.                                     /* Bypass input filter */
    82.                                     IOCON_PIO_SMODE_BYPASS |
    83.                                     /* IOCONCLKDIV0 */
    84.                                     IOCON_PIO_CLKDIV0);
    85.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_6, SPI_LCD_MOSI);
    86.    
    87.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_13, SPI_LCD_MOSI);  //RGB_IO=MOSI
    88.    
    89.     const uint32_t SPI_MISO = (/* Selects pull-up function */
    90.                                     0 |
    91.                                     /* Enable hysteresis */
    92.                                     IOCON_PIO_HYS_EN |
    93.                                     /* Input not invert */
    94.                                     IOCON_PIO_INV_DI |
    95.                                     /* Disables Open-drain function */
    96.                                     IOCON_PIO_OD_DI |
    97.                                     /* Bypass input filter */
    98.                                     IOCON_PIO_SMODE_BYPASS |
    99.                                     /* IOCONCLKDIV0 */
    100.                                     IOCON_PIO_CLKDIV0);
    101.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_9, SPI_MISO);   //f_miso

    102.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_8,   spilcd_ioc);    //f_cs
    103.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_12,  spilcd_ioc);   //f_clk
    104.     IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_13,  spilcd_ioc);   //f_mosi
    105.    
    106.     CLOCK_EnableClock(kCLOCK_Swm);
    107.    
    108.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI0_SCK,   kSWM_PortPin_P1_19);
    109.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI0_MOSI,  kSWM_PortPin_P0_6);
    110.    
    111.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MOSI,  kSWM_PortPin_P1_13);
    112.    
    113.     /* Disable clock for switch matrix. */
    114.     CLOCK_DisableClock(kCLOCK_Swm);
    115.    
    116.     spi_master_config_t userConfig = {0};
    117.     uint32_t srcFreq               = 0U;
    118.     /* Note: The slave board using interrupt way, slave will spend more time to write data
    119.      *       to TX register, to prevent TX data missing in slave, we will add some delay between
    120.      *       frames and capture data at the second edge, this operation will make the slave
    121.      *       has more time to prapare the data.
    122.      */
    123.    
    124.     SPI_MasterGetDefaultConfig(&userConfig);
    125.     userConfig.baudRate_Bps           = 30000000;
    126.     userConfig.sselNumber             = kSPI_Ssel0Assert;
    127.     userConfig.clockPolarity          = kSPI_ClockPolarityActiveHigh;
    128.     userConfig.clockPhase             = kSPI_ClockPhaseFirstEdge;
    129.     userConfig.direction              = kSPI_MsbFirst;
    130.     userConfig.delayConfig.preDelay   = 0x0U;
    131.     userConfig.delayConfig.postDelay  = 0x0U;
    132.     userConfig.delayConfig.frameDelay = 0x0U;
    133.     userConfig.delayConfig.transferDelay = 0x0U;
    134.     srcFreq                           = CLOCK_GetFreq(kCLOCK_MainClk);
    135.     SPI_MasterInit(SPI0, &userConfig, srcFreq);
    136.    
    137.     userConfig.baudRate_Bps           = 6000000;
    138.     SPI_MasterInit(SPI1, &userConfig, srcFreq);

    139. }




    140. SPI_Type * spi_table[2]=
    141. {
    142.     SPI0,
    143.     SPI1,
    144. };

    145. void spi_pre_h(void)
    146. {
    147.     CLOCK_EnableClock(kCLOCK_Swm);
    148.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MISO,  kSWM_PortPin_P1_9);  //F_MISO
    149.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MOSI,  kSWM_PortPin_P0_13); //F_MOSI
    150.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_SCK ,  kSWM_PortPin_P0_12); //F_CLK
    151.     CLOCK_DisableClock(kCLOCK_Swm);
    152.     SPI_MasterSetBaudRate(SPI1,30000000, CLOCK_GetFreq(kCLOCK_MainClk));
    153. }

    154. void spi_pre_l(void)
    155. {
    156.     CLOCK_EnableClock(kCLOCK_Swm);
    157.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MOSI,  kSWM_PortPin_P1_13); //RGB_IO
    158.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MISO,  0XFF);  //
    159.     SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_SCK ,  0XFF);  //
    160.     CLOCK_DisableClock(kCLOCK_Swm);
    161.     SPI_MasterSetBaudRate(SPI1,6000000, CLOCK_GetFreq(kCLOCK_MainClk));
    162. }

    163. void spi_writebyte(uint8_t index,uint8_t TxData)
    164. {
    165.     spi_table[index]->TXDATCTL = TxData | 0X077E0000;
    166.     while ((spi_table[index]->STAT & SPI_STAT_TXRDY_MASK) == 0U){;}
    167. }

    168. uint8_t spi_readbyte(uint8_t index)
    169. {
    170.     uint8_t re;
    171.     spi_table[index]->TXDATCTL = 0xff | 0X073E0000;
    172.     while ((spi_table[index]->STAT & SPI_STAT_RXRDY_MASK) == 0U){;}
    173.     re = spi_table[index]->RXDAT & 0XFF;
    174.     return re;
    175. }


    176. uint8_t spi_writebuff(uint8_t index,uint8_t *buff,uint32_t len)
    177. {
    178.     volatile uint32_t i;
    179.     for(i=0; i<len; i++)
    180.     {
    181.         spi_writebyte(index,buff[i]);
    182.     }   
    183.     return 0;
    184. }

    185. uint8_t spi_readbuff(uint8_t index,uint8_t *buff,uint32_t len)
    186. {
    187.     volatile uint32_t i;
    188.     for(i=0; i<len; i++)
    189.     {
    190.         buff[i] = spi_readbyte(index);
    191.     }   
    192.     return 0;
    193. }

    194. void spi_write_read(uint8_t index,uint8_t * wbuf,uint32_t wl,uint8_t * rbuf,uint32_t rl)
    195. {
    196.     if((wbuf != NULL) && (wl != 0))
    197.     {
    198.         while(wl--)
    199.         {
    200.             spi_writebyte(index,*wbuf++);
    201.         }
    202.     }

    203.     if((rbuf != NULL) && (rl != 0))
    204.     {
    205.         while(rl--)
    206.         {
    207.             *rbuf++ = spi_readbyte(index);
    208.         }
    209.     }
    210. }
    复制代码
    W25QXX的驱动是以前写好的,直接拿来用,主要实现了SPI读写接口就行。

    下面对W25QXX flash读写测试一下。
    主要测试代码:
    1.     for (int i = 0; i < BUFFER_SIZE; i++)
    2.     {
    3.         txBuffer[i] = i % 256;
    4.         rxBuffer[i] = 0U;
    5.     }
    6.     DbgConsole_Printf("W25QXX Erase Chip.\r\n");
    7.     W25QXX_EraseChip();
    8.     DbgConsole_Printf("W25QXX Read Data.\r\n");
    9.     W25QXX_Read(0,rxBuffer,64);
    10.     for (int i = 0; i < BUFFER_SIZE; i++)
    11.     {
    12.         DbgConsole_Printf("%02X ",rxBuffer[i]);
    13.     }
    14.     DbgConsole_Printf("W25QXX Write Data.\r\n");
    15.     W25QXX_Write_NoCheck(0,txBuffer,BUFFER_SIZE);
    16.     DbgConsole_Printf("W25QXX Read Data to Check.\r\n");
    17.     for (int j = 0; j < BUFFER_SIZE; j++)
    18.     {
    19.         W25QXX_Read(0 + j*BUFFER_SIZE,rxBuffer,64);
    20.         for (int i = 0; i < BUFFER_SIZE; i++)
    21.         {
    22.             DbgConsole_Printf("%02X ",rxBuffer[i]);
    23.         }
    24.         DbgConsole_Printf("\n");
    25.     }
    复制代码


    通过串口观察数据,写入和读出一致。
    3.jpg

    好了,本次到此结束。
    下一期会讲如何写spi flash下载算法。



    评分

    参与人数 1NXP金币 +5 收起 理由
    xiaoshen-372360 + 5 很给力!

    查看全部评分

    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3922

    主题

    7540

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39978
    最后登录
    2025-8-21
    发表于 2022-10-27 09:57:27 | 显示全部楼层
    赞一波
    qiandao qiandao
    回复

    使用道具 举报

  • TA的每日心情
    开心
    5 天前
  • 签到天数: 729 天

    连续签到: 1 天

    [LV.9]以坛为家II

    14

    主题

    2687

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    4635
    最后登录
    2025-8-23
    发表于 2022-10-27 12:34:17 | 显示全部楼层
    666,大佬就是厉害
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2024-9-13 10:02
  • 签到天数: 297 天

    连续签到: 1 天

    [LV.8]以坛为家I

    34

    主题

    3512

    帖子

    38

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    6074

    活跃会员

    最后登录
    2025-7-30
    发表于 2022-10-27 14:46:04 | 显示全部楼层

    666,大佬就是厉害
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2025-8-8 16:43
  • 签到天数: 1504 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    97

    主题

    4692

    帖子

    12

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    10093
    最后登录
    2025-8-8
    发表于 2022-10-27 15:14:41 | 显示全部楼层
    学习了一下。
    话说为什么会有两种速度的SPI配置呀
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    15 分钟前
  • 签到天数: 2406 天

    连续签到: 115 天

    [LV.Master]伴坛终老

    84

    主题

    2万

    帖子

    3

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    22340
    最后登录
    2025-8-24
     楼主| 发表于 2022-10-27 16:11:08 | 显示全部楼层
    jobszheng5 发表于 2022-10-27 15:14
    学习了一下。
    话说为什么会有两种速度的SPI配置呀

    flash和WS2812数字灯共用SPI在,速度不同所以要切换速度。
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2022-12-28 11:05
  • 签到天数: 49 天

    连续签到: 1 天

    [LV.5]常住居民I

    0

    主题

    111

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    387
    最后登录
    2023-12-29
    发表于 2022-10-28 14:32:30 | 显示全部楼层
    学习一波
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-24 19:31 , Processed in 0.099038 second(s), 27 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表