加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入

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

05/20 20:02
1459
服務(wù)支持:
技術(shù)交流群

完成交易后在“購買成功”頁面掃碼入群,即可與技術(shù)大咖們分享疑惑和經(jīng)驗(yàn)、收獲成長和認(rèn)同、領(lǐng)取優(yōu)惠和紅包等。

虛擬商品不可退

當(dāng)前內(nèi)容為數(shù)字版權(quán)作品,購買后不支持退換且無法轉(zhuǎn)移使用。

加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論
放大
電路板圖(3)
相關(guān)方案
  • 方案介紹
  • 相關(guān)文件
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

上篇搞定了W25Qxx SPIFLASH的驅(qū)動,這次就想想把keil的下載算法搞一搞,后面方便存儲下載一些資源了。

下面就參考論壇關(guān)于keil的flash下載算法內(nèi)容:

編寫Keil的自定義Flash燒寫算法FLM:https://www.nxpic.org.cn/module/forum/forum.php?mod=viewthread&tid=629295&fromuid=3327992

(出處: 恩智浦技術(shù)社區(qū))

淺析Keil MDK下的串行Flash下載算法設(shè)計:https://www.nxpic.org.cn/module/forum/forum.php?mod=viewthread&tid=621135&fromuid=3327992

(出處: 恩智浦技術(shù)社區(qū))

使用keil的下載算法模板工程,在keil安裝目錄的ARM/FLASH下??截惸0骞こ坛鰜?,添加flash的驅(qū)動以及MCU初始化文件。

下載算法主要是修改FlashPrg.c和FlashDev.c內(nèi)的接口文件,然后就是MCU的初始化。

首先是FlashDev.c文件,這里面主要提供了一些Flash的基本硬件信息,定義了諸如Flash器件名,sector大小,寫入塊大小等。下面就是我修改的結(jié)構(gòu)體信息。

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下載的接口函數(shù)了。

// 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);

下面就是我修改的接口函數(shù)

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);
}

下面看看模板工程的設(shè)置

編譯之后就可以得到下載算法文件了。把下載算法文件復(fù)制到keil目錄ARM/FLASH下,后面就可以用了。

下載算法工程。

lpc845_spiflash_flm.rar (136.32 KB)

  • lpc845_spiflash_flm.rar

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
XRCGB32M000F1H00R0 1 Murata Manufacturing Co Ltd Parallel - Fundamental Quartz Crystal, 32MHz Nom, SMD, 3 PIN

ECAD模型

下載ECAD模型
$0.55 查看
CY62167EV30LL-45ZXIT 1 Cypress Semiconductor Standard SRAM, 1MX16, 45ns, CMOS, PDSO48, 12 X 18.40 MM, 1 MM HEIGHT, MO-142, ROHS COMPLIANT, TSOP1-48
$18.79 查看
TLP185(GR,SE 1 Toshiba America Electronic Components TRANSISTOR OUTPUT OPTOCOUPLER

ECAD模型

下載ECAD模型
$0.39 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜