加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入

【LPC845月饼板】+搞定W25Qxx SPIFLASH的keil下载算法(一)

05/20 20:02
1147
服务支持:
技术交流群

完成交易后在“购买成功”页面扫码入群,即可与技术大咖们分享疑惑和经验、收获成长和认同、领取优惠和红包等。

虚拟商品不可退

当前内容为数字版权作品,购买后不支持退换且无法转移使用。

加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论
放大
电路板图(3)
相关方案
  • 方案介绍
  • 相关文件
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

上篇搞定了W25Qxx SPIFLASH的驱动,这次就想想把keil的下载算法搞一搞,后面方便存储下载一些资源了。

下面就参考论坛关于keil的flash下载算法内容:

编写Keil的自定义Flash烧写算法FLM:https://www.nxpic.org.cn/module/forum/forum.php?mod=viewthread&tid=629295&fromuid=3327992

(出处: 恩智浦技术社区)

浅析Keil MDK下的串行Flash下载算法设计:https://www.nxpic.org.cn/module/forum/forum.php?mod=viewthread&tid=621135&fromuid=3327992

(出处: 恩智浦技术社区)

使用keil的下载算法模板工程,在keil安装目录的ARM/FLASH下。拷贝模板工程出来,添加flash的驱动以及MCU初始化文件。

下载算法主要是修改FlashPrg.c和FlashDev.c内的接口文件,然后就是MCU的初始化。

首先是FlashDev.c文件,这里面主要提供了一些Flash的基本硬件信息,定义了诸如Flash器件名,sector大小,写入块大小等。下面就是我修改的结构体信息。

struct FlashDevice const FlashDevice  =  {
   FLASH_DRV_VERS,             // Driver Version, do not modify!
   "LPC845_Mooncake_SPIFLASH", // Device Name 
   EXTSPI,                     // Device Type
   0x30000000,                 // Device Start Address
   0x01000000,                 // Device Size in Bytes (25Q128=16M)
   4096,                       // Programming Page Size
   0,                          // Reserved, must be 0
   0xFF,                       // Initial Content of Erased Memory
   10000,                        // Program Page Timeout 100 mSec
   10000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
   0x001000, 0x000000,         // Sector Size  4kB (8 Sectors)
   SECTOR_END
};

然后就是FlashPrg.c文件flash下载的接口函数了。

// Flash Programming Functions (Called by FlashOS)
extern          int  Init        (unsigned long adr,   // Initialize Flash
                                  unsigned long clk,
                                  unsigned long fnc);
extern          int  UnInit      (unsigned long fnc);  // De-initialize Flash
extern          int  BlankCheck  (unsigned long adr,   // Blank Check
                                  unsigned long sz,
                                  unsigned char pat);
extern          int  EraseChip   (void);               // Erase complete Device
extern          int  EraseSector (unsigned long adr);  // Erase Sector Function
extern          int  ProgramPage (unsigned long adr,   // Program Page Function
                                  unsigned long sz,
                                  unsigned char *buf);
extern unsigned long Verify      (unsigned long adr,   // Verify Function
                                  unsigned long sz,
                                  unsigned char *buf);

下面就是我修改的接口函数

void w25qxx_gpio_init(void)
{
    CLOCK_EnableClock(kCLOCK_Iocon);
    CLOCK_EnableClock(kCLOCK_Gpio0);
    CLOCK_EnableClock(kCLOCK_Gpio1);

    gpio_pin_config_t SPILCD_IN_config = {
        .pinDirection = kGPIO_DigitalInput,
        .outputLogic = 1U,
    };
    gpio_pin_config_t SPILCD_IOH_config = {
        .pinDirection = kGPIO_DigitalOutput,
        .outputLogic = 1U,
    };
    gpio_pin_config_t SPILCD_IOL_config = {
        .pinDirection = kGPIO_DigitalOutput,
        .outputLogic = 0U,
    };
    /* Initialize GPIO functionality on pin */
    
    GPIO_PinInit(GPIO, 1,8, &SPILCD_IOH_config); //FLASH_CS
    GPIO_PinInit(GPIO, 1,9, &SPILCD_IN_config); //FLASH_MISO
    GPIO_PinInit(GPIO, 0,12, &SPILCD_IOH_config);//FLASH_CLK
    GPIO_PinInit(GPIO, 0,13, &SPILCD_IOH_config);//FLASH_MOSI
    
    const uint32_t spilcd_ioc = (/* Selects pull-up function */
                              IOCON_PIO_MODE_PULLUP |
                              /* Enable hysteresis */
                              IOCON_PIO_HYS_EN |
                              /* Input not invert */
                              IOCON_PIO_INV_DI |
                              /* Disables Open-drain function */
                              IOCON_PIO_OD_DI |
                              /* Bypass input filter */
                              IOCON_PIO_SMODE_BYPASS |
                              /* IOCONCLKDIV0 */
                              IOCON_PIO_CLKDIV0); 
        
    const uint32_t SPI_MISO = (/* Selects pull-up function */
                                    0 |
                                    /* Enable hysteresis */
                                    IOCON_PIO_HYS_EN |
                                    /* Input not invert */
                                    IOCON_PIO_INV_DI |
                                    /* Disables Open-drain function */
                                    IOCON_PIO_OD_DI |
                                    /* Bypass input filter */
                                    IOCON_PIO_SMODE_BYPASS |
                                    /* IOCONCLKDIV0 */
                                    IOCON_PIO_CLKDIV0);
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_9, SPI_MISO);   //f_miso

    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_8,   spilcd_ioc);   //f_cs
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_12,  spilcd_ioc);   //f_clk
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_13,  spilcd_ioc);   //f_mosi
    
    CLOCK_EnableClock(kCLOCK_Swm);
    SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MISO,  kSWM_PortPin_P1_9);  //F_MISO
    SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MOSI,  kSWM_PortPin_P0_13); //F_MOSI
    SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_SCK ,  kSWM_PortPin_P0_12); //F_CLK
    CLOCK_DisableClock(kCLOCK_Swm);
    
    CLOCK_EnableClock(kCLOCK_Spi1);
    CLOCK_Select(kSPI1_Clk_From_MainClk);
    RESET_PeripheralReset(kSPI1_RST_N_SHIFT_RSTn);
    
    SPI1->CFG = 0x05;
    SPI1->DLY = 0;
    SPI1->DIV = 0;
    
}

#define IOCON_PIO_CLKDIV0       0x00u       /*!<@brief IOCONCLKDIV0 */
#define IOCON_PIO_HYS_EN        0x20u       /*!<@brief Enable hysteresis */
#define IOCON_PIO_I2CMODE_FAST  0x00u       /*!<@brief Standard/Fast mode */
#define IOCON_PIO_INV_DI        0x00u       /*!<@brief Input not invert */
#define IOCON_PIO_MODE_PULLUP   0x10u       /*!<@brief Selects pull-up function */
#define IOCON_PIO_OD_DI         0x00u       /*!<@brief Disables Open-drain function */
#define IOCON_PIO_SMODE_BYPASS  0x00u       /*!<@brief Bypass input filter */

void usart_send_str(char *s,int len)
{
    for(int i=0;i<len;i++){
        while (0U == (USART0->STAT & USART_STAT_TXRDY_MASK))   {; }
        USART0->TXDAT = *s++;
    }
}

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {

    /* Add your Code */
    extern void BOARD_BootClockFRO30M(void);
    BOARD_BootClockFRO30M();
    W25QXX_Init();
    
    gpio_pin_config_t LED_config = {
        .pinDirection = kGPIO_DigitalOutput,
        .outputLogic = 1U,
    };
    GPIO_PinInit(GPIO, 0, 0, &LED_config);
    const uint32_t LED_RED = (/* Selects pull-up function */
                              IOCON_PIO_MODE_PULLUP |
                              /* Enable hysteresis */
                              IOCON_PIO_HYS_EN |
                              /* Input not invert */
                              IOCON_PIO_INV_DI |
                              /* Disables Open-drain function */
                              IOCON_PIO_OD_DI |
                              /* Bypass input filter */
                              IOCON_PIO_SMODE_BYPASS |
                              /* IOCONCLKDIV0 */
                              IOCON_PIO_CLKDIV0);
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_0, LED_RED);
    GPIO->CLR[0] = (1u << 0);


    /* Enables clock for switch matrix.: enable */
    CLOCK_EnableClock(kCLOCK_Swm);
    const uint32_t DEBUG_UART_RX = (/* Selects pull-up function */
                                    IOCON_PIO_MODE_PULLUP |
                                    /* Enable hysteresis */
                                    IOCON_PIO_HYS_EN |
                                    /* Input not invert */
                                    IOCON_PIO_INV_DI |
                                    /* Disables Open-drain function */
                                    IOCON_PIO_OD_DI |
                                    /* Bypass input filter */
                                    IOCON_PIO_SMODE_BYPASS |
                                    /* IOCONCLKDIV0 */
                                    IOCON_PIO_CLKDIV0);
    /* PIO1 PIN16 (coords: 36) is configured as USART0, RXD. */
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_24, DEBUG_UART_RX);

    const uint32_t DEBUG_UART_TX = (/* Selects pull-up function */
                                    IOCON_PIO_MODE_PULLUP |
                                    /* Enable hysteresis */
                                    IOCON_PIO_HYS_EN |
                                    /* Input not invert */
                                    IOCON_PIO_INV_DI |
                                    /* Disables Open-drain function */
                                    IOCON_PIO_OD_DI |
                                    /* Bypass input filter */
                                    IOCON_PIO_SMODE_BYPASS |
                                    /* IOCONCLKDIV0 */
                                    IOCON_PIO_CLKDIV0);
    /* PIO1 PIN17 (coords: 37) is configured as USART0, TXD. */
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_25, DEBUG_UART_TX);
    /* USART0_TXD connect to P0_25 */
    SWM_SetMovablePinSelect(SWM0, kSWM_USART0_TXD, kSWM_PortPin_P0_25);
    /* USART0_RXD connect to P0_24 */
    SWM_SetMovablePinSelect(SWM0, kSWM_USART0_RXD, kSWM_PortPin_P0_24);
    /* Disable clock for switch matrix. */
    CLOCK_DisableClock(kCLOCK_Swm);
    
    CLOCK_EnableClock(kCLOCK_Uart0);
    CLOCK_Select(kUART0_Clk_From_MainClk);
    RESET_PeripheralReset(kUART0_RST_N_SHIFT_RSTn);
    USART0->CFG = 0x05;
    USART0->BRG = 0x13;
    USART0->OSR = 0x0c;
    
    USART0->TXDAT = 0xaa;
    return (0);                                  // Finished without Errors
}

/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int UnInit (unsigned long fnc) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip (void) {

  /* Add your Code */
    USART0->TXDAT = 0x55;
    GPIO->SET[0] = (1u << 0);
    W25QXX_EraseChip();
    GPIO->CLR[0] = (1u << 0);
  return (0);                                  // Finished without Errors
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector (unsigned long adr) {

  /* Add your Code */
//    usart_send_str((char *)adr,4);
    USART0->TXDAT = 0x5a;
    GPIO->SET[0] = (1u << 0);
    W25QXX_EraseSector(adr-0x30000000);
    GPIO->CLR[0] = (1u << 0);
  return (0);                                  // Finished without Errors
}


/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {

  /* Add your Code */
//    usart_send_str((char *)adr,4);
//    usart_send_str((char *)sz,4);
//    USART0->TXDAT = buf[0];
    GPIO->SET[0] = (1u << 0);
    W25QXX_Write_NoCheck(adr-0x30000000,buf,sz);
    GPIO->CLR[0] = (1u << 0);
  return (0);                                  // Finished without Errors
}


unsigned long Verify      ( unsigned long adr,   // Verify Function
                            unsigned long sz,
                            unsigned char *buf)
{
//    unsigned long i=0;
//    unsigned char buff[16];
//    USART0->TXDAT = buf[0];
//    while(i<sz)
//    {
//        W25QXX_Read(adr-0x30000000 + i,buff, 16);
//        for(int j=0;j<16;j++)
//        {
//            if(buff[j] != buf[i+j])
//            {
//                return adr+i+j;
//            }
//        }        
//        i+=16;
//    }
  return (adr+sz);
}

int  BlankCheck  (unsigned long adr,   // Blank Check
                    unsigned long sz,
                    unsigned char pat)
{
    USART0->TXDAT = 0x5f;
  return (0);
}

下面看看模板工程的设置

编译之后就可以得到下载算法文件了。把下载算法文件复制到keil目录ARM/FLASH下,后面就可以用了。

下载算法工程。

lpc845_spiflash_flm.rar (136.32 KB)

  • lpc845_spiflash_flm.rar

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
CWX813-100.0M 1 Connor-Winfield LVCMOS Output Clock Oscillator, 100MHz Nom,

ECAD模型

下载ECAD模型
暂无数据 查看
HFBR-1412TZ 1 Foxconn Transmitter, 792nm Min, 865nm Max, 5Mbps, ST Connector, DIP, Panel Mount, Through Hole Mount, ROHS COMPLIANT PACKAGE
$24 查看
CX5032GA08000D0PTWZ1 1 Kyocera AVX Components Quartz Crystal, QUARTZ CRYSTAL RESONATOR, 8 MHz, ROHS COMPLIANT, CERAMIC PACKAGE-2
暂无数据 查看

相关推荐

电子产业图谱