W25Q16 Flash Chip 을 사용하기 위해서 먼저 데이터 시트를 한번 읽어보심을 추천 드립니다
W25Q16 Flash Datasheet.pdf
1.76MB
저는 Flash memory가 삽입된 STM32F407VET 보드를 이용했습니다 ^^;;
회로도도 한번 참고하세요
STM32_F4VE_SCHEMATIC.PDF
1.28MB
회로도를 보시면 SPI1을 사용하는걸 알수 있고, CS핀을 PB0으로 사용함을 확인하셔야 합니다.
기본적으로 CS핀을 이용해서 RESET, SET을 반복하며 커맨드를 입력함을 데이터시트를 보면 알수 있습니다.
설정부분을 유심히 보시기 바랍니다.
prescaler를 꼭 체크하세요...
40MB/s 로 동작함으로 4이상으로 세팅하셔야 해요 ^^
저는 안정적으로 8- 즉 10.5MBits/s 로 설정하였습니다.
그리고 코드를 보시죠.
동작을 천천히 Command와 데이터시트를 비교해보면서 확인하면 동작을 이해하는데 도움이 됩니다~
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define SectorSize 0x1000
#define PageSize 256
#define SectorCount 15 * 16
#define PageCount (SectorCount * SectorSize) / PageSize
#define BlockSize SectorSize * 16
#define CapacityInKiloByte SectorCount * SectorSize / 1024;
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t buffer1[128];
uint8_t buffer2[128];
uint8_t uniqID[8];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
int _write(int file, char* p, int len)
{
HAL_UART_Transmit(&huart1, p, len, 10);
return len;
}
uint32_t flash_SectorToPage(uint32_t SectorAddress);
uint32_t flash_BlockToPage(uint32_t BlockAddress);
void flash_wait_end(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t flash_spi(uint8_t data)
{
uint8_t ret;
HAL_SPI_TransmitReceive(&hspi1, &data, &ret, 1, 100);
return ret;
}
void flash_write_enable(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x06);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
HAL_Delay(1);
}
void flash_write_disable(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x04);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
HAL_Delay(1);
}
void flash_write_byte(uint8_t pBuffer, uint32_t WriteAddr_inBytes)
{
flash_wait_end();
flash_write_enable();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x02);
flash_spi((WriteAddr_inBytes & 0xFF0000) >> 16);
flash_spi((WriteAddr_inBytes & 0xFF00) >> 8);
flash_spi(WriteAddr_inBytes & 0xFF);
flash_spi(pBuffer);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
flash_wait_end();
}
void flash_write_page(uint8_t* pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_PageSize)
{
if(((NumByteToWrite_up_to_PageSize + OffsetInByte) > PageSize) || (NumByteToWrite_up_to_PageSize == 0))
NumByteToWrite_up_to_PageSize = PageSize - OffsetInByte;
if((OffsetInByte + NumByteToWrite_up_to_PageSize) > PageSize)
NumByteToWrite_up_to_PageSize = PageSize - OffsetInByte;
flash_wait_end();
flash_write_enable();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x02);
Page_Address = (Page_Address * PageSize) + OffsetInByte;
flash_spi((Page_Address & 0xFF0000) >> 16);
flash_spi((Page_Address & 0xFF00) >> 8);
flash_spi(Page_Address & 0xFF);
HAL_SPI_Transmit(&hspi1, pBuffer, NumByteToWrite_up_to_PageSize, 100);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
flash_wait_end();
HAL_Delay(1);
}
void flash_write_sector(uint8_t* pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_SectorSize)
{
if((NumByteToWrite_up_to_SectorSize > SectorSize) || (NumByteToWrite_up_to_SectorSize == 0))
NumByteToWrite_up_to_SectorSize = SectorSize;
uint32_t StartPage;
int32_t BytesToWrite;
uint32_t LocalOffset;
if((OffsetInByte + NumByteToWrite_up_to_SectorSize) > SectorSize)
BytesToWrite = SectorSize - OffsetInByte;
else
BytesToWrite = NumByteToWrite_up_to_SectorSize;
StartPage = flash_SectorToPage(Sector_Address) + (OffsetInByte / PageSize);
LocalOffset = OffsetInByte % PageSize;
do
{
flash_write_page(pBuffer, StartPage, LocalOffset, BytesToWrite);
StartPage++;
BytesToWrite -= PageSize - LocalOffset;
pBuffer += PageSize - LocalOffset;
LocalOffset = 0;
}while(BytesToWrite > 0);
}
void flash_write_block(uint8_t* pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_BlockSize)
{
if((NumByteToWrite_up_to_BlockSize > BlockSize) || (NumByteToWrite_up_to_BlockSize == 0))
NumByteToWrite_up_to_BlockSize = BlockSize;
uint32_t StartPage;
int32_t BytesToWrite;
uint32_t LocalOffset;
if((OffsetInByte + NumByteToWrite_up_to_BlockSize) > BlockSize)
BytesToWrite = BlockSize - OffsetInByte;
else
BytesToWrite = NumByteToWrite_up_to_BlockSize;
StartPage = flash_BloackToPage(Block_Address) + (OffsetInByte / PageSize);
LocalOffset = OffsetInByte % PageSize;
do
{
flash_write_page(pBuffer, StartPage, LocalOffset, BytesToWrite);
StartPage++;
BytesToWrite -= PageSize-LocalOffset;
pBuffer += PageSize - LocalOffset;
LocalOffset=0;
}while(BytesToWrite > 0);
}
uint32_t flash_SectorToPage(uint32_t SectorAddress)
{
return (SectorAddress * SectorSize) / PageSize;
}
uint32_t flash_BlockToPage(uint32_t BlockAddress)
{
return (BlockAddress * BlockSize) / PageSize;
}
void flash_wait_end(void)
{
uint8_t stat = 0;
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x05);
do
{
stat = flash_spi(0xA5);
HAL_Delay(1);
}
while((stat & 0x01) == 0x01);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET); // CS to low
}
void flash_read_byte(uint8_t* pBuffer, uint32_t Bytes_Address)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x0B);
flash_spi((Bytes_Address & 0xFF0000) >> 16);
flash_spi((Bytes_Address & 0xFF00) >> 8);
flash_spi(Bytes_Address & 0xFF);
flash_spi(0);
*pBuffer = flash_spi(0xA5);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
printf("read 0x%02X\n", *pBuffer);
}
void flash_read_bytes(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x0B);
flash_spi((ReadAddr & 0xFF0000) >> 16);
flash_spi((ReadAddr& 0xFF00) >> 8);
flash_spi(ReadAddr & 0xFF);
flash_spi(0);
HAL_SPI_Receive(&hspi1, pBuffer, NumByteToRead, 2000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
HAL_Delay(1);
}
void flash_read_page(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_PageSize)
{
if((NumByteToRead_up_to_PageSize > PageSize) || (NumByteToRead_up_to_PageSize == 0))
NumByteToRead_up_to_PageSize = PageSize;
if((OffsetInByte + NumByteToRead_up_to_PageSize) > PageSize)
NumByteToRead_up_to_PageSize = PageSize - OffsetInByte;
Page_Address = Page_Address * PageSize + OffsetInByte;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x0B);
flash_spi((Page_Address & 0xFF0000) >> 16);
flash_spi((Page_Address& 0xFF00) >> 8);
flash_spi(Page_Address & 0xFF);
flash_spi(0);
HAL_SPI_Receive(&hspi1, pBuffer, NumByteToRead_up_to_PageSize, 100);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
HAL_Delay(1);
}
void flash_read_sector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_SectorSize)
{
if((NumByteToRead_up_to_SectorSize > SectorSize) || (NumByteToRead_up_to_SectorSize == 0))
NumByteToRead_up_to_SectorSize = SectorSize;
uint32_t StartPage;
int32_t BytesToRead;
uint32_t LocalOffset;
if((OffsetInByte + NumByteToRead_up_to_SectorSize) > SectorSize)
BytesToRead = SectorSize - OffsetInByte;
else
BytesToRead = NumByteToRead_up_to_SectorSize;
StartPage = flash_SectorToPage(Sector_Address) + (OffsetInByte / PageSize);
LocalOffset = OffsetInByte % PageSize;
do
{
flash_read_page(pBuffer, StartPage, LocalOffset, BytesToRead);
StartPage++;
BytesToRead -= PageSize - LocalOffset;
pBuffer += PageSize - LocalOffset;
LocalOffset=0;
}while(BytesToRead>0);
}
void flash_read_block(uint8_t* pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_BlockSize)
{
if((NumByteToRead_up_to_BlockSize > BlockSize) || (NumByteToRead_up_to_BlockSize == 0))
NumByteToRead_up_to_BlockSize = BlockSize;
uint32_t StartPage;
int32_t BytesToRead;
uint32_t LocalOffset;
if((OffsetInByte + NumByteToRead_up_to_BlockSize) > BlockSize)
BytesToRead = BlockSize - OffsetInByte;
else
BytesToRead = NumByteToRead_up_to_BlockSize;
StartPage = flash_BlockToPage(Block_Address) + (OffsetInByte / PageSize);
LocalOffset = OffsetInByte % PageSize;
do
{
flash_read_page(pBuffer, StartPage, LocalOffset, BytesToRead);
StartPage++;
BytesToRead -= PageSize-LocalOffset;
pBuffer += PageSize - LocalOffset;
LocalOffset=0;
}while(BytesToRead > 0);
}
uint8_t flash_read_Status(uint8_t register_num)
{
uint8_t status = 0;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
if(register_num == 1)
{
flash_spi(0x05);
status = flash_spi(0xA5);
}
else if(register_num == 2)
{
flash_spi(0x35);
status = flash_spi(0xA5);
}
else
{
flash_spi(0x15);
status = flash_spi(0xA5);
}
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
return status;
}
void flash_erase_chip(void)
{
flash_write_enable();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0xC7);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
flash_wait_end();
HAL_Delay(10);
}
void flash_erase_sector(uint32_t SectorAddr)
{
flash_wait_end();
SectorAddr = SectorAddr * SectorSize;
flash_write_enable();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0x20);
flash_spi((SectorAddr & 0xFF0000) >> 16);
flash_spi((SectorAddr & 0xFF00) >> 8);
flash_spi(SectorAddr & 0xFF);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
flash_wait_end();
HAL_Delay(1);
}
void flash_erase_block(uint32_t BlockAddr)
{
flash_wait_end();
BlockAddr = BlockAddr * SectorSize * 16;
flash_write_enable();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, RESET); // CS to low
flash_spi(0xD8);
flash_spi((BlockAddr & 0xFF0000) >> 16);
flash_spi((BlockAddr & 0xFF00) >> 8);
flash_spi(BlockAddr & 0xFF);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, SET);
flash_wait_end();
HAL_Delay(1);
}
uint32_t flash_read_ID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
flash_spi(0x9F);
Temp0 = flash_spi(0xA5);
Temp1 = flash_spi(0xA5);
Temp2 = flash_spi(0xA5);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
void flash_read_uniqID(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
flash_spi(0x4B);
for(uint8_t i=0; i<4; i++)
flash_spi(0x4B);
for(uint8_t i=0; i<8; i++)
uniqID[i] = flash_spi(0x4B);;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
for(uint8_t i=0; i<8; i++)
printf("%X", uniqID[i]);
printf("\n");
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
HAL_SPI_MspInit(&hspi1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
uint8_t cnt = 10;
flash_erase_sector(1);
for(uint8_t i=0; i<128; i++)
buffer1[i] = cnt++;
flash_write_sector(buffer1, 1, 0, 128);
flash_read_sector(buffer2, 1, 0, 128);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for(uint8_t i=0; i<128; i++)
{
printf("%d\n", buffer2[i]);
HAL_Delay(10);
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
반응형
'b. 임베디드 > STM32' 카테고리의 다른 글
[Mikromedia+ for STM32 ARM] MCP9700 온도센서 ADC 출력 (1) | 2020.08.31 |
---|---|
[Mikromedia+ for STM32 ARM] UART Polling과 printf (0) | 2020.08.29 |
[Mikromedia+ for STM32 ARM] GPIO 테스트 (0) | 2020.08.27 |
[Mikromedia+ for STM32 ARM] 업로드를 위한 2가지 방법 (0) | 2020.08.26 |
[STM32F407VGT Discovery] SPI with MAX41100 사용하기 (0) | 2019.06.29 |
[STM32F407VGT Discovery] ADC Interrupt 사용하기 (0) | 2019.06.26 |
[STM32F407VGT Discovery] ADC Single Conversion(Polling) 사용하기 (0) | 2019.06.25 |
[STM32F407VGT Discovery] USART printf 사용하기 (0) | 2019.06.24 |