/*
* Author: Pawel Jablonski
* E-mail: pj@xirx.net
* WWW: xirx.net
* GIT: git.xirx.net
*
* License: You can use this code however you like
* but leave information about the original author.
* Code is free for non-commercial and commercial use.
*/
#include <stm32f0xx.h>
#include <stm32f0xx_hal.h>
#include <stm32f0xx_hal_gpio.h>
#include <stm32f0xx_hal_rcc.h>
#include <stm32f0xx_hal_spi.h>
#include <system_stm32f0xx.h>
#include "type.h"
#include "flash.h"
#define FLASH_TIMEOUT 100 //!< SPI HAL maximum time to process an operation
#define FLASH_REG_STATUS 0xD7 //!< Status register address for the flash
#define FLASH_STATUS_READY 0x80 //!< Ready status bit of the flash
#define FLASH_STATUS_PAGE_SIZE_512 0x01 //!< 512 bytes sector is set bit of the flash
#define FLASH_READ_SECTOR 0x53 //!< Read data from the flash to the internal buffer operation code
#define FLASH_WRITE_SECTOR 0x83 //!< Write data from the internal buffer to the flash operation code
#define FLASH_READ_BUFFER 0xd4 //!< Read data from the internal buffer operation code
#define FLASH_WRITE_BUFFER 0x84 //!< Write data to the internal buffer operation code
static void flashLock(void);
static void flashUnlock(void);
static unsigned char flashGetStatus(void);
static bool flashReadSector(unsigned int sector);
static bool flashWriteSector(unsigned int sector);
static bool flashReadBuffer(unsigned int sector, unsigned char *buffer);
static bool flashWriteBuffer(unsigned int sector, unsigned char *buffer);
static SPI_HandleTypeDef spiHandle; //!< SPI HAL handle
static volatile bool mutex; //!< Mutex lock for operations on the flash
//! Init flash and set up the SPI
void flashInit(void)
{
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitTypeDef gpioInit = {0};
gpioInit.Pin = GPIO_PIN_13;
gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
gpioInit.Pull = GPIO_NOPULL;
gpioInit.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &gpioInit);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
__HAL_RCC_GPIOA_CLK_ENABLE();
gpioInit.Pin = (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpioInit.Mode = GPIO_MODE_AF_PP;
gpioInit.Pull = GPIO_NOPULL;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
gpioInit.Alternate = GPIO_AF0_SPI2;
HAL_GPIO_Init(GPIOA, &gpioInit);
__HAL_RCC_SPI1_CLK_ENABLE();
spiHandle.Instance = SPI1;
spiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
spiHandle.Init.Mode = SPI_MODE_MASTER;
spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
spiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
spiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
spiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
spiHandle.Init.Direction = SPI_DIRECTION_2LINES;
spiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
spiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
spiHandle.Init.CRCPolynomial = 7;
spiHandle.Init.NSS = SPI_NSS_SOFT;
HAL_SPI_Init(&spiHandle);
__HAL_SPI_ENABLE(&spiHandle);
while(1)
{
unsigned char status = flashGetStatus();
if(!(status & FLASH_STATUS_READY))
{
continue;
}
if(!(status & FLASH_STATUS_PAGE_SIZE_512))
{
unsigned char buf[4] = { 0x3d, 0x2a, 0x80, 0xa6 };
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_Transmit(&spiHandle, buf, 4, FLASH_TIMEOUT);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
}
else
{
break;
}
}
}
/**
* Read a sector data from the flash
*
* @param sector Sector number
* @param buffer Buffer to write data from the flash
*
* @return Status of the operation
*/
bool flashRead(unsigned int sector, unsigned char *buffer)
{
flashLock();
if(sector > FLASH_SECTOR_QUANTITY)
{
return(FALSE);
}
if(!flashReadBuffer(sector, buffer))
{
flashUnlock();
return(FALSE);
}
flashUnlock();
return(TRUE);
}
/**
* Write a sector data to the flash
*
* @param sector Sector number
* @param buffer Buffer with data to write into the flash
*
* @return Status of the operation
*/
bool flashWrite(unsigned int sector, unsigned char *buffer)
{
flashLock();
if(sector > FLASH_SECTOR_QUANTITY)
{
return(FALSE);
}
if(!flashWriteBuffer(sector, buffer))
{
flashUnlock();
return(FALSE);
}
flashUnlock();
return(TRUE);
}
//! Lock access to the flash
static void flashLock(void)
{
while(1)
{
__disable_irq();
if(!mutex)
{
mutex = TRUE;
break;
}
__enable_irq();
for(volatile int i = 0; i < 100; i++);
}
}
//! Unlock access to the flash
static void flashUnlock(void)
{
__disable_irq();
{
mutex = FALSE;
}
__enable_irq();
}
/**
* Get status of the flash
*
* @return Status of the flash
*/
static unsigned char flashGetStatus(void)
{
unsigned char address = FLASH_REG_STATUS;
unsigned char status = 0;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_Transmit(&spiHandle, &address, 1, FLASH_TIMEOUT);
HAL_SPI_Receive(&spiHandle, &status, 1, FLASH_TIMEOUT);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
return(status);
}
/**
* Read a sector data from the flash to the internal buffer of the flash
*
* @param sector Sector number
*
* @return Status of the operation
*/
static bool flashReadSector(unsigned int sector)
{
if(sector >= FLASH_SECTOR_QUANTITY)
{
return(FALSE);
}
unsigned char buf[4] = { FLASH_READ_SECTOR, (unsigned char)((sector >> 7) & 0x7f), (unsigned char)((sector << 1) & 0xfe), 0x00 };
while(!(flashGetStatus() & FLASH_STATUS_READY));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_Transmit(&spiHandle, buf, 4, FLASH_TIMEOUT);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
while(!(flashGetStatus() & FLASH_STATUS_READY));
return(TRUE);
}
/**
* Write a sector data from the internal buffer of the flash to the flash
*
* @param sector Sector number
*
* @return Status of the operation
*/
static bool flashWriteSector(unsigned int sector)
{
if(sector >= FLASH_SECTOR_QUANTITY)
{
return(FALSE);
}
unsigned char buf[4] = { FLASH_WRITE_SECTOR, (unsigned char)((sector >> 7) & 0x7f), (unsigned char)((sector << 1) & 0xfe), 0x00 };
while(!(flashGetStatus() & FLASH_STATUS_READY));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_Transmit(&spiHandle, buf, 4, FLASH_TIMEOUT);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
while(!(flashGetStatus() & FLASH_STATUS_READY));
return(TRUE);
}
/**
* Read a sector data from the internal buffer of the flash
*
* @param sector Sector number
* @param buffer Buffer to write data from the internal buffer of the flash
*
* @return Status of the operation
*/
static bool flashReadBuffer(unsigned int sector, unsigned char *buffer)
{
if(sector >= FLASH_SECTOR_QUANTITY)
{
return(FALSE);
}
if(!flashReadSector(sector))
{
return(FALSE);
}
unsigned char buf[5] = { FLASH_READ_BUFFER, 0x00, 0x00, 0x00, 0x00 };
while(!(flashGetStatus() & FLASH_STATUS_READY));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_Transmit(&spiHandle, buf, 5, FLASH_TIMEOUT);
HAL_SPI_Receive(&spiHandle, buffer, FLASH_SECTOR_SIZE, FLASH_TIMEOUT);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
while(!(flashGetStatus() & FLASH_STATUS_READY));
return(TRUE);
}
/**
* Write a sector data into the internal buffer of the flash
*
* @param sector Sector number
* @param buffer Buffer with data to write into the internal buffer of the flash
*
* @return Status of the operation
*/
static bool flashWriteBuffer(unsigned int sector, unsigned char *buffer)
{
if(sector >= FLASH_SECTOR_QUANTITY)
{
return(FALSE);
}
unsigned char buf[4] = { FLASH_WRITE_BUFFER, 0x00, 0x00, 0x00 };
while(!(flashGetStatus() & FLASH_STATUS_READY));
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_Transmit(&spiHandle, buf, 4, FLASH_TIMEOUT);
HAL_SPI_Transmit(&spiHandle, buffer, FLASH_SECTOR_SIZE, FLASH_TIMEOUT);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
while(!(flashGetStatus() & FLASH_STATUS_READY));
if(!flashWriteSector(sector))
{
return(FALSE);
}
return(TRUE);
}