/** * @brief Execute the whole chip * @returns 0 if successful, -1 if unable to claim bus */ int32_t PIOS_Flash_Jedec_EraseChip() { if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; uint8_t ret; uint8_t out[] = {flash_dev->cfg->chip_erase}; if((ret = PIOS_Flash_Jedec_WriteEnable()) != 0) return ret; if(PIOS_Flash_Jedec_ClaimBus() != 0) return -1; if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(); return -2; } PIOS_Flash_Jedec_ReleaseBus(); // Keep polling when bus is busy too int i = 0; while(PIOS_Flash_Jedec_Busy() != 0) { #if defined(FLASH_FREERTOS) vTaskDelay(1); #endif if ((i++) % 10000 == 0) PIOS_LED_Toggle(PIOS_LED_HEARTBEAT); } return 0; }
/** * @brief Erase a sector on the flash chip * @param[in] add Address of flash to erase * @returns 0 if successful * @retval -1 if unable to claim bus * @retval */ static int32_t PIOS_Flash_Jedec_EraseSector(uintptr_t flash_id, uint32_t addr) { struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id; if (PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; uint8_t ret; uint8_t out[] = {flash_dev->cfg->sector_erase, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff}; if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0) return ret; if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0) return -1; if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -2; } PIOS_Flash_Jedec_ReleaseBus(flash_dev); // Keep polling when bus is busy too while (PIOS_Flash_Jedec_Busy(flash_dev) != 0) { #if defined(FLASH_FREERTOS) vTaskDelay(1); #endif } return 0; }
/** * @brief Release the SPI bus sempahore and ensure flash chip not using bus */ static int32_t PIOS_Flash_Jedec_ReleaseBus() { if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; PIOS_SPI_RC_PinSet(flash_dev->spi_id, flash_dev->slave_num, 1); PIOS_SPI_ReleaseBus(flash_dev->spi_id); flash_dev->claimed = false; return 0; }
/** * @brief Release the semaphore to perform a transaction * @return 0 for success, -1 for timeout */ int32_t PIOS_Flash_Jedec_EndTransaction() { #if defined(FLASH_FREERTOS) if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; if(xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE) return -1; #endif return 0; }
/** * @brief Grab the semaphore to perform a transaction * @return 0 for success, -1 for timeout */ int32_t PIOS_Flash_Jedec_StartTransaction() { #if defined(FLASH_FREERTOS) if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; if(xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE) return -1; #endif return 0; }
/** * @brief Execute the write enable instruction and returns the status * @returns 0 if successful, -1 if unable to claim bus */ static int32_t PIOS_Flash_Jedec_WriteEnable() { if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; uint8_t out[] = {JEDEC_WRITE_ENABLE}; if(PIOS_Flash_Jedec_ClaimBus() != 0) return -1; PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL); PIOS_Flash_Jedec_ReleaseBus(); return 0; }
/** * @brief Claim the SPI bus for flash use and assert CS pin * @return 0 for sucess, -1 for failure to get semaphore */ static int32_t PIOS_Flash_Jedec_ClaimBus() { if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; if(PIOS_SPI_ClaimBus(flash_dev->spi_id) < 0) return -1; PIOS_SPI_RC_PinSet(flash_dev->spi_id, flash_dev->slave_num, 0); flash_dev->claimed = true; return 0; }
/** * @brief Release the semaphore to perform a transaction * @return 0 for success, -1 for timeout */ static int32_t PIOS_Flash_Jedec_EndTransaction(uintptr_t flash_id) { struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id; if (PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; #if defined(PIOS_INCLUDE_FREERTOS) if (xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE) return -2; #endif return 0; }
/** * @brief Grab the semaphore to perform a transaction * @return 0 for success, -1 for timeout */ static int32_t PIOS_Flash_Jedec_StartTransaction(uintptr_t flash_id) { struct jedec_flash_dev *flash_dev = (struct jedec_flash_dev *)flash_id; if (PIOS_Flash_Jedec_Validate(flash_dev) != 0) { return -1; } #if defined(PIOS_INCLUDE_FREERTOS) if (xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE) { return -2; } #endif return 0; }
/** * @brief Read the status register from flash chip and return it */ int32_t PIOS_Flash_Jedec_ReadStatus() { if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; uint8_t out[2] = {JEDEC_READ_STATUS, 0}; uint8_t in[2] = {0,0}; if(PIOS_Flash_Jedec_ClaimBus() < 0) return -1; if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,in,sizeof(out),NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(); return -2; } PIOS_Flash_Jedec_ReleaseBus(); return in[1]; }
/** * @brief Write one page of data (up to 256 bytes) aligned to a page start * @param[in] addr Address in flash to write to * @param[in] data Pointer to data to write to flash * @param[in] len Length of data to write (max 256 bytes) * @return Zero if success or error code * @retval -1 Unable to claim SPI bus * @retval -2 Size exceeds 256 bytes * @retval -3 Length to write would wrap around page boundary */ static int32_t PIOS_Flash_Jedec_WriteData(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len) { struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id; if(PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; uint8_t ret; uint8_t out[4] = {JEDEC_PAGE_WRITE, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff}; /* Can only write one page at a time */ if (len > 0x100) return -2; /* Ensure number of bytes fits after starting address before end of page */ if (((addr & 0xff) + len) > 0x100) return -3; if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0) return ret; /* Execute write page command and clock in address. Keep CS asserted */ if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0) return -1; if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -1; } /* Clock out data to flash */ if (PIOS_SPI_TransferBlock(flash_dev->spi_id,data,NULL,len,NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -1; } PIOS_Flash_Jedec_ReleaseBus(flash_dev); // Keep polling when bus is busy too #if defined(FLASH_FREERTOS) while (PIOS_Flash_Jedec_Busy(flash_dev) != 0) { vTaskDelay(1); } #else // Query status this way to prevent accel chip locking us out if (PIOS_Flash_Jedec_ClaimBus(flash_dev) < 0) return -1; PIOS_SPI_TransferByte(flash_dev->spi_id, JEDEC_READ_STATUS); while (PIOS_SPI_TransferByte(flash_dev->spi_id, JEDEC_READ_STATUS) & JEDEC_STATUS_BUSY); PIOS_Flash_Jedec_ReleaseBus(flash_dev); #endif return 0; } /** * @brief Write multiple chunks of data in one transaction * @param[in] addr Address in flash to write to * @param[in] data Pointer to data to write to flash * @param[in] len Length of data to write (max 256 bytes) * @return Zero if success or error code * @retval -1 Unable to claim SPI bus * @retval -2 Size exceeds 256 bytes * @retval -3 Length to write would wrap around page boundary */ static int32_t PIOS_Flash_Jedec_WriteChunks(uintptr_t flash_id, uint32_t addr, struct pios_flash_chunk chunks[], uint32_t num) { struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id; if (PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; uint8_t ret; uint8_t out[4] = {JEDEC_PAGE_WRITE, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff}; /* Can only write one page at a time */ uint32_t len = 0; for (uint32_t i = 0; i < num; i++) len += chunks[i].len; if (len > 0x100) return -2; /* Ensure number of bytes fits after starting address before end of page */ if (((addr & 0xff) + len) > 0x100) return -3; if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0) return ret; /* Execute write page command and clock in address. Keep CS asserted */ if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0) return -1; if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -1; } for (uint32_t i = 0; i < num; i++) { struct pios_flash_chunk * chunk = &chunks[i]; /* Clock out data to flash */ if (PIOS_SPI_TransferBlock(flash_dev->spi_id,chunk->addr,NULL,chunk->len,NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -1; } } PIOS_Flash_Jedec_ReleaseBus(flash_dev); // Skip checking for busy with this to get OS running again fast return 0; } /** * @brief Read data from a location in flash memory * @param[in] addr Address in flash to write to * @param[in] data Pointer to data to write from flash * @param[in] len Length of data to write (max 256 bytes) * @return Zero if success or error code * @retval -1 Unable to claim SPI bus */ static int32_t PIOS_Flash_Jedec_ReadData(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len) { struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id; if (PIOS_Flash_Jedec_Validate(flash_dev) != 0) return -1; if (PIOS_Flash_Jedec_ClaimBus(flash_dev) == -1) return -1; /* Execute read command and clock in address. Keep CS asserted */ uint8_t out[] = {JEDEC_READ_DATA, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff}; if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -2; } /* Copy the transfer data to the buffer */ if (PIOS_SPI_TransferBlock(flash_dev->spi_id,NULL,data,len,NULL) < 0) { PIOS_Flash_Jedec_ReleaseBus(flash_dev); return -3; } PIOS_Flash_Jedec_ReleaseBus(flash_dev); return 0; } /* Provide a flash driver to external drivers */ const struct pios_flash_driver pios_jedec_flash_driver = { .start_transaction = PIOS_Flash_Jedec_StartTransaction, .end_transaction = PIOS_Flash_Jedec_EndTransaction, .erase_chip = PIOS_Flash_Jedec_EraseChip, .erase_sector = PIOS_Flash_Jedec_EraseSector, .write_chunks = PIOS_Flash_Jedec_WriteChunks, .write_data = PIOS_Flash_Jedec_WriteData, .read_data = PIOS_Flash_Jedec_ReadData, };