上篇搞定了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)