Study/STM32F

SPI 로 M25PXX (Flash,eeprom) 사용하기

Answer Choi 2015. 2. 12. 10:46
반응형



 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();를 쓰셔서 읽어오시면 됩니다.


반응형