SPI 로 M25PXX (Flash,eeprom) 사용하기
M25Pxx 시리즈 flash는 SPI를 사용하는데, 막상 하려면 조금 까다롭습니다.
참고할만한 소스가 ST에서 제공하는 STM32F1 개발보드용 소스가 있습니다.
첨부로 넣어두었는데, ST에 가셔도 받을 수 있는 자료이고요, 압축을 푸셔서 Examples\SPI\M25P64_FLASH\
에 가시면 예제소스가 있습니다. main.c와 spi_flash.c ,spi_flash.h 파일을 자신의 보드에 맞게 수정하시면 됩니다.
우선 헤더파일인 spi_flash.h 파일만 수정해주시면 될 것같아요.
개발보드에 따라 포트 바뀌게 되어있는데 아래와 같이바꾸시면 개발보드 상관없이 쓸 수 있습니다.
헤더파일 수정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __SPI_FLASH_H #define __SPI_FLASH_H /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ #define GPIO_CS GPIOA #define RCC_APB2Periph_GPIO_CS RCC_APB2Periph_GPIOA #define GPIO_Pin_CS GPIO_Pin_4 /* Exported macro ------------------------------------------------------------*/ /* Select SPI FLASH: Chip Select pin low */ #define SPI_FLASH_CS_LOW() GPIO_ResetBits(GPIO_CS, GPIO_Pin_CS) /* Deselect SPI FLASH: Chip Select pin high */ #define SPI_FLASH_CS_HIGH() GPIO_SetBits(GPIO_CS, GPIO_Pin_CS) /* Exported functions ------------------------------------------------------- */ /*----- High layer function -----*/ void SPI_FLASH_Init(void); void SPI_FLASH_SectorErase(u32 SectorAddr); void SPI_FLASH_BulkErase(void); void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite); void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite); void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead); u32 SPI_FLASH_ReadID(void); void SPI_FLASH_StartReadSequence(u32 ReadAddr); /*----- Low layer function -----*/ u8 SPI_FLASH_ReadByte(void); u8 SPI_FLASH_SendByte(u8 byte); u16 SPI_FLASH_SendHalfWord(u16 HalfWord); void SPI_FLASH_WriteEnable(void); void SPI_FLASH_WaitForWriteEnd(void); #endif /* __SPI_FLASH_H */ /******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ | cs |
전 SPI1번을 사용하니깐 SPI1로 설정했습니다.
초기화!!
초기화는 별다른 것 없습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | void SPI_FLASH_Init(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable SPI1 and GPIO clocks */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIO_CS, ENABLE); /* Configure SPI1 pins: SCK, MISO and MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure I/O for Flash Chip select */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CS; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIO_CS, &GPIO_InitStructure); /* Deselect the FLASH: Chip Select high */ SPI_FLASH_CS_HIGH(); /* SPI1 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); /* Enable SPI1 */ SPI_Cmd(SPI1, ENABLE); } | cs |
SPI1을 사용하시면 위와같이 아니면 포트를 바꿔주시면 됩니다.
플래시 쓰기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) { /* Enable the write access to the FLASH */ SPI_FLASH_WriteEnable(); /* Select the FLASH: Chip Select low */ SPI_FLASH_CS_LOW(); /* Send "Write to Memory " instruction */ SPI_FLASH_SendByte(WRITE); /* Send WriteAddr high nibble address byte to write to */ SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16); /* Send WriteAddr medium nibble address byte to write to */ SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8); /* Send WriteAddr low nibble address byte to write to */ SPI_FLASH_SendByte(WriteAddr & 0xFF); /* while there is data to be written on the FLASH */ while (NumByteToWrite--) { /* Send the current byte */ SPI_FLASH_SendByte(*pBuffer); /* Point on the next byte to be written */ pBuffer++; } /* Deselect the FLASH: Chip Select high */ SPI_FLASH_CS_HIGH(); /* Wait the end of Flash writing */ SPI_FLASH_WaitForWriteEnd(); } | cs |
플래시에 쓰는건 SPI_FLASH_PageWrite 함수를 쓰시면 됩니다.
파라메터값은 각각 플래시에 쓸 버퍼,쓸 주소, 쓸 길이 입니다.
예제에는 main.c에 SPI_FLASH_PageWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize); 가 제공됩니다.
FLASH_WriteAddress만 수정해서 그대로 사용하시면 결과를 보실 수 있습니다.
플래시 읽기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead) { /* Select the FLASH: Chip Select low */ SPI_FLASH_CS_LOW(); /* Send "Read from Memory " instruction */ SPI_FLASH_SendByte(READ); /* Send ReadAddr high nibble address byte to read from */ SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16); /* Send ReadAddr medium nibble address byte to read from */ SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8); /* Send ReadAddr low nibble address byte to read from */ SPI_FLASH_SendByte(ReadAddr & 0xFF); while (NumByteToRead--) /* while there is data to be read */ { /* Read a byte from the FLASH */ *pBuffer = SPI_FLASH_SendByte(Dummy_Byte); /* Point to the next location where the byte read will be saved */ pBuffer++; } /* Deselect the FLASH: Chip Select high */ SPI_FLASH_CS_HIGH(); } | cs |
플래시읽기 역시 SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize); 를 제공합니다.
플래시 ID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | u32 SPI_FLASH_ReadID(void) { u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0; /* Select the FLASH: Chip Select low */ SPI_FLASH_CS_LOW(); /* Send "RDID " instruction */ SPI_FLASH_SendByte(0x9F); /* Read a byte from the FLASH */ Temp0 = SPI_FLASH_SendByte(Dummy_Byte); /* Read a byte from the FLASH */ Temp1 = SPI_FLASH_SendByte(Dummy_Byte); /* Read a byte from the FLASH */ Temp2 = SPI_FLASH_SendByte(Dummy_Byte); /* Deselect the FLASH: Chip Select high */ SPI_FLASH_CS_HIGH(); Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2; return Temp; } | cs |
플래시 ID 또한 FLASH_ID = SPI_FLASH_ReadID();를 쓰셔서 읽어오시면 됩니다.