/* * 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 #include #include #include #include #include #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); }