本來(lái)準(zhǔn)備移植ARM2D圖形的,例子還沒(méi)準(zhǔn)備好,下次再說(shuō)。今天就說(shuō)說(shuō)如何驅(qū)動(dòng)SPI flash吧。 LPC845月餅板上有一塊spi flash,主要是為了存儲(chǔ)一些資源數(shù)據(jù)等等。LPC845本身flash不夠多,到時(shí)想做一些lcd顯示圖片字體的話,資源會(huì)不足。后面還會(huì)說(shuō)說(shuō)如何編寫(xiě)flash的下載算法。下載算法已經(jīng)基本調(diào)好了,可以直接下載數(shù)據(jù)到flash上了。
進(jìn)入正題,下面說(shuō)一下如何驅(qū)動(dòng)spi flash。
要驅(qū)動(dòng)spiflash,首先看看原理圖,找到IO管腳,然后初始化管腳,初始化SPI。電路圖部分如下:
這里要說(shuō)明一下,LPC845只有2個(gè)SPI外設(shè)。lcd屏幕用了一個(gè)SPI0,上期WS2812燈用了一個(gè)SPI1.所以這個(gè)SPIFLASH只能和他們共用一個(gè)SPI外設(shè)了。我這里是WS2812和SPIFLASH共用SPI1在,分時(shí)復(fù)用。
下面是spi初始化部分:
void drv_spi_gpio_init(void)
{
CLOCK_EnableClock(kCLOCK_Iocon);
CLOCK_EnableClock(kCLOCK_Gpio0);
CLOCK_EnableClock(kCLOCK_Gpio1);
CLOCK_EnableClock(kCLOCK_Spi0);
CLOCK_EnableClock(kCLOCK_Spi1);
CLOCK_Select(kSPI0_Clk_From_MainClk);
CLOCK_Select(kSPI1_Clk_From_MainClk);
RESET_PeripheralReset(kSPI0_RST_N_SHIFT_RSTn);
RESET_PeripheralReset(kSPI1_RST_N_SHIFT_RSTn);
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, 0, 7, &SPILCD_IOL_config);//LCD_BLK
GPIO_PinInit(GPIO, 1, 6, &SPILCD_IOH_config);//LCD_DC
GPIO_PinInit(GPIO, 1, 7, &SPILCD_IOH_config);//LCD_RST
GPIO_PinInit(GPIO, 1,18, &SPILCD_IOH_config);//LCD_CS
GPIO_PinInit(GPIO, 1,19, &SPILCD_IOH_config);//LCD_CLK
GPIO_PinInit(GPIO, 0, 6, &SPILCD_IOH_config);//LCD_MOSI
GPIO_PinInit(GPIO, 1,13, &SPILCD_IOH_config);//RGB_MOSI
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);
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_7, spilcd_ioc);
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_6, spilcd_ioc);
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_7, spilcd_ioc);
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_18, spilcd_ioc);
/* Enables clock for switch matrix.: enable */
const uint32_t SPI_LCD_CLK = (/* 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_PIO1_19, SPI_LCD_CLK);
const uint32_t SPI_LCD_MOSI = (/* 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_6, SPI_LCD_MOSI);
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_13, SPI_LCD_MOSI); //RGB_IO=MOSI
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_SPI0_SCK, kSWM_PortPin_P1_19);
SWM_SetMovablePinSelect(SWM0, kSWM_SPI0_MOSI, kSWM_PortPin_P0_6);
SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MOSI, kSWM_PortPin_P1_13);
/* Disable clock for switch matrix. */
CLOCK_DisableClock(kCLOCK_Swm);
spi_master_config_t userConfig = {0};
uint32_t srcFreq = 0U;
/* Note: The slave board using interrupt way, slave will spend more time to write data
* to TX register, to prevent TX data missing in slave, we will add some delay between
* frames and capture data at the second edge, this operation will make the slave
* has more time to prapare the data.
*/
SPI_MasterGetDefaultConfig(&userConfig);
userConfig.baudRate_Bps = 30000000;
userConfig.sselNumber = kSPI_Ssel0Assert;
userConfig.clockPolarity = kSPI_ClockPolarityActiveHigh;
userConfig.clockPhase = kSPI_ClockPhaseFirstEdge;
userConfig.direction = kSPI_MsbFirst;
userConfig.delayConfig.preDelay = 0x0U;
userConfig.delayConfig.postDelay = 0x0U;
userConfig.delayConfig.frameDelay = 0x0U;
userConfig.delayConfig.transferDelay = 0x0U;
srcFreq = CLOCK_GetFreq(kCLOCK_MainClk);
SPI_MasterInit(SPI0, &userConfig, srcFreq);
userConfig.baudRate_Bps = 6000000;
SPI_MasterInit(SPI1, &userConfig, srcFreq);
}
SPI_Type * spi_table[2]=
{
SPI0,
SPI1,
};
void spi_pre_h(void)
{
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);
SPI_MasterSetBaudRate(SPI1,30000000, CLOCK_GetFreq(kCLOCK_MainClk));
}
void spi_pre_l(void)
{
CLOCK_EnableClock(kCLOCK_Swm);
SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MOSI, kSWM_PortPin_P1_13); //RGB_IO
SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_MISO, 0XFF); //
SWM_SetMovablePinSelect(SWM0, kSWM_SPI1_SCK , 0XFF); //
CLOCK_DisableClock(kCLOCK_Swm);
SPI_MasterSetBaudRate(SPI1,6000000, CLOCK_GetFreq(kCLOCK_MainClk));
}
void spi_writebyte(uint8_t index,uint8_t TxData)
{
spi_table[index]->TXDATCTL = TxData | 0X077E0000;
while ((spi_table[index]->STAT & SPI_STAT_TXRDY_MASK) == 0U){;}
}
uint8_t spi_readbyte(uint8_t index)
{
uint8_t re;
spi_table[index]->TXDATCTL = 0xff | 0X073E0000;
while ((spi_table[index]->STAT & SPI_STAT_RXRDY_MASK) == 0U){;}
re = spi_table[index]->RXDAT & 0XFF;
return re;
}
uint8_t spi_writebuff(uint8_t index,uint8_t *buff,uint32_t len)
{
volatile uint32_t i;
for(i=0; i<len; i++)
{
spi_writebyte(index,buff[i]);
}
return 0;
}
uint8_t spi_readbuff(uint8_t index,uint8_t *buff,uint32_t len)
{
volatile uint32_t i;
for(i=0; i<len; i++)
{
buff[i] = spi_readbyte(index);
}
return 0;
}
void spi_write_read(uint8_t index,uint8_t * wbuf,uint32_t wl,uint8_t * rbuf,uint32_t rl)
{
if((wbuf != NULL) && (wl != 0))
{
while(wl--)
{
spi_writebyte(index,*wbuf++);
}
}
if((rbuf != NULL) && (rl != 0))
{
while(rl--)
{
*rbuf++ = spi_readbyte(index);
}
}
}
W25QXX的驅(qū)動(dòng)是以前寫(xiě)好的,直接拿來(lái)用,主要實(shí)現(xiàn)了SPI讀寫(xiě)接口就行。
下面對(duì)W25QXX flash讀寫(xiě)測(cè)試一下。
主要測(cè)試代碼:
for (int i = 0; i < BUFFER_SIZE; i++)
{
txBuffer[i] = i % 256;
rxBuffer[i] = 0U;
}
DbgConsole_Printf("W25QXX Erase Chip.rn");
W25QXX_EraseChip();
DbgConsole_Printf("W25QXX Read Data.rn");
W25QXX_Read(0,rxBuffer,64);
for (int i = 0; i < BUFFER_SIZE; i++)
{
DbgConsole_Printf("%02X ",rxBuffer[i]);
}
DbgConsole_Printf("W25QXX Write Data.rn");
W25QXX_Write_NoCheck(0,txBuffer,BUFFER_SIZE);
DbgConsole_Printf("W25QXX Read Data to Check.rn");
for (int j = 0; j < BUFFER_SIZE; j++)
{
W25QXX_Read(0 + j*BUFFER_SIZE,rxBuffer,64);
for (int i = 0; i < BUFFER_SIZE; i++)
{
DbgConsole_Printf("%02X ",rxBuffer[i]);
}
DbgConsole_Printf("n");
}
通過(guò)串口觀察數(shù)據(jù),寫(xiě)入和讀出一致。
好了,本次到此結(jié)束。