1 /* -------------------------------- Arctic Core ------------------------------
\r
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
\r
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
\r
6 * This source code is free software; you can redistribute it and/or modify it
\r
7 * under the terms of the GNU General Public License version 2 as published by the
\r
8 * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
\r
10 * This program is distributed in the hope that it will be useful, but
\r
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
\r
14 * -------------------------------- Arctic Core ------------------------------*/
\r
26 /* CONFIGURATION NOTES
\r
27 * The configuration is simple, use the template supplied.
\r
28 * Changing the configuration is NOT recommended.
\r
32 * - Variant PB is supported not PC ( FLS203,FLS204 )
\r
33 * - Since DEM is NOT supported all those requirements are not supported.
\r
34 * - AC is not supported since it makes no sense for a SPI flash.
\r
38 /* IMPLEMENTATION NOTES
\r
39 * - The only SPI flash supported is the SST25VF016B although the
\r
40 * entire SST25XX should work through configuration changes
\r
41 * - Commands that are used by this module are:
\r
42 * WREN,WRDI,WRSR,byte write and erase 4K
\r
43 * - AC is not supported since the there's no use for it.
\r
44 * - Supports 64 bytes read, byte write and 4K erase
\r
45 * - The implementation very much dependent on the configuration
\r
46 * of the SPI( Spi_Cfg.c )
\r
47 * - Calls from SPI are not checked( Only makes sense if DEM is supported )
\r
54 #include "Fls_SST25xx.h"
\r
57 #if defined(USE_DEM)
\r
62 //#include <stdio.h>
\r
65 //#define USE_LDEBUG_PRINTF
\r
67 #define MODULE_NAME "/driver/Fls_25"
\r
70 /* The width in bytes used by this flash */
\r
71 #define ADDR_LENGTH 3
\r
73 /* Helper macro for the process function */
\r
74 #define SET_STATE(_done,_state) done=(_done);job->state=(_state)
\r
76 /* How many loops to wait for SPI to go back to "normal" state after
\r
77 * read/write/erase */
\r
78 #define TIMER_BUSY_WAIT 100000
\r
80 #if FLS_SST25XX_DEV_ERROR_DETECT
\r
81 #define FLS_VALIDATE_PARAM_ADDRESS_SECTOR_W_RV(_addr, _api, _rv)\
\r
84 Fls_SectorType sector;\
\r
85 for (sectorIndex=0; sectorIndex<Fls_SST25xx_Global.config->FlsSectorListSize;sectorIndex++) {\
\r
86 sector = Fls_SST25xx_Global.config->FlsSectorList[sectorIndex];\
\r
87 if((((uint32)_addr-sector.FlsSectorStartaddress) / sector.FlsSectorSize)<sector.FlsNumberOfSectors){\
\r
88 /* Within the right adress space */\
\r
89 if (!(((uint32)_addr-sector.FlsSectorStartaddress) % sector.FlsSectorSize)){\
\r
90 /* Address is correctly aligned */\
\r
97 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_ADDRESS ); \
\r
101 #define FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(_addr, _api, _rv)\
\r
104 Fls_SectorType sector;\
\r
105 for (sectorIndex=0; sectorIndex<Fls_SST25xx_Global.config->FlsSectorListSize;sectorIndex++) {\
\r
106 sector = Fls_SST25xx_Global.config->FlsSectorList[sectorIndex];\
\r
107 if((((uint32)_addr-sector.FlsSectorStartaddress) / sector.FlsSectorSize)<sector.FlsNumberOfSectors){\
\r
108 /* Within the right adress space */\
\r
109 if (!(((uint32)_addr-sector.FlsSectorStartaddress) % sector.FlsPageSize)){\
\r
110 /* Address is correctly aligned */\
\r
117 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_ADDRESS ); \
\r
121 #define FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(_addr, _length, _api, _rv)\
\r
124 const Fls_SectorType* sectorPtr= &Fls_SST25xx_Global.config->FlsSectorList[0];\
\r
125 for (i=0; i<Fls_SST25xx_Global.config->FlsSectorListSize;i++) {\
\r
126 if ((sectorPtr->FlsSectorStartaddress + (sectorPtr->FlsNumberOfSectors * sectorPtr->FlsSectorSize))>=(uint32_t)(_addr+(_length))){\
\r
127 if ((0!=_length)&&!(_length % sectorPtr->FlsPageSize)){\
\r
135 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_LENGTH ); \
\r
139 #define FLS_VALIDATE_PARAM_LENGTH_SECTOR_W_RV(_addr, _length, _api, _rv)\
\r
142 const Fls_SectorType* sectorPtr= &Fls_SST25xx_Global.config->FlsSectorList[0];\
\r
143 for (i=0; i<Fls_SST25xx_Global.config->FlsSectorListSize;i++) {\
\r
144 if ((sectorPtr->FlsSectorStartaddress + (sectorPtr->FlsNumberOfSectors * sectorPtr->FlsSectorSize))>=(uint32_t)(_addr+(_length))){\
\r
145 if ((0!=_length)&& !(_length % sectorPtr->FlsSectorSize)){\
\r
153 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_LENGTH ); \
\r
157 #define FLS_VALIDATE_STATUS_UNINIT_W_RV(_status, _api, _rv)\
\r
158 if (MEMIF_UNINIT == _status){\
\r
159 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_UNINIT); \
\r
163 #define FLS_VALIDATE_STATUS_BUSY(_status, _api)\
\r
164 if (MEMIF_BUSY == _status){\
\r
165 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_BUSY); \
\r
169 #define FLS_VALIDATE_STATUS_BUSY_W_RV(_status, _api, _rv)\
\r
170 if (MEMIF_BUSY == _status){\
\r
171 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_BUSY); \
\r
175 #define FLS_VALIDATE_PARAM_DATA_W_RV(_ptr,_api, _rv) \
\r
176 if( (_ptr)==((void *)0)) { \
\r
177 Det_ReportError(MODULE_ID_FLS,0,_api,FLS_E_PARAM_DATA); \
\r
181 #define FLS_VALIDATE_PARAM_ADDRESS_SECTOR_W_RV(_addr, _api, _rv)
\r
182 #define FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(_addr, _api, _rv)
\r
183 #define FLS_VALIDATE_PARAM_LENGTH_SECTOR_W_RV(_addr, _length, _api, _rv)
\r
184 #define FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(_addr, _length, _api, _rv)
\r
185 #define FLS_VALIDATE_STATUS_UNINIT_W_RV(_status, _api, _rv)
\r
186 #define FLS_VALIDATE_STATUS_BUSY(_status, _api)
\r
187 #define FLS_VALIDATE_STATUS_BUSY_W_RV(_status, _api, _rv)
\r
188 #define FLS_VALIDATE_PARAM_DATA_W_RV(_ptr,_api,_rv)
\r
191 #if ( FLS_DEV_ERROR_DETECT == STD_ON )
\r
192 #define VALIDATE_CONFIG(_x) assert(_x)
\r
193 #define DET_REPORTERROR(_x,_y,_z,_q) Det_ReportError(MODULE_ID_FLS, _y, _z, _q)
\r
195 #define VALIDATE_CONFIG(_x)
\r
196 #define DET_REPORTERROR(_x,_y,_z,_q)
\r
199 #if ( FLS_GET_JOB_RESULT_API == STD_ON )
\r
200 #define FEE_JOB_END_NOTIFICATION() \
\r
201 if( Fls_SST25xx_Global.config->FlsJobEndNotification != NULL ) { \
\r
202 Fls_SST25xx_Global.config->FlsJobEndNotification(); \
\r
204 #define FEE_JOB_ERROR_NOTIFICATION() \
\r
205 if( Fls_SST25xx_Global.config->FlsJobErrorNotification != NULL ) { \
\r
206 Fls_SST25xx_Global.config->FlsJobErrorNotification(); \
\r
209 #define FEE_JOB_END_NOTIFICATION()
\r
210 #define FEE_JOB_ERROR_NOTIFICATION()
\r
215 #if ( FLS_SST25XX_DEV_ERROR_DETECT == STD_ON ) // Report DEV errors
\r
216 #define VALIDATE(_exp,_api,_err ) \
\r
218 Det_ReportError(MODULE_ID_FLS,0,_api,_err); \
\r
223 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \
\r
225 Det_ReportError(MODULE_ID_FLS,0,_api,_err); \
\r
229 #define VALID_CHANNEL(_ch) ( Gpt_Global.configured & (1<<(_ch)) )
\r
231 #else // Validate but do not report
\r
232 #define VALIDATE(_exp,_api,_err )\
\r
236 #define VALIDATE_W_RV(_exp,_api,_err,_rv )\
\r
242 const Fls_ConfigType* _Fls_SST25xx_ConfigPtr;
\r
244 #if ( FLS_SST25XX_VERSION_INFO_API == STD_ON )
\r
245 static Std_VersionInfoType Fls_SST25XX_VersionInfo = {
\r
246 .vendorID = (uint16)1,
\r
247 .moduleID = (uint16) MODULE_ID_FLS,
\r
248 .instanceID = (uint8)1,
\r
249 /* Vendor numbers */
\r
250 .sw_major_version = (uint8)FLS_SST25XX_SW_MAJOR_VERSION,
\r
251 .sw_minor_version = (uint8)FLS_SST25XX_SW_MINOR_VERSION,
\r
252 .sw_patch_version = (uint8)FLS_SST25XX_SW_PATCH_VERSION,
\r
253 .ar_major_version = (uint8)FLS_SST25XX_AR_MAJOR_VERSION,
\r
254 .ar_minor_version = (uint8)FLS_SST25XX_AR_MINOR_VERSION,
\r
255 .ar_patch_version = (uint8)FLS_SST25XX_AR_PATCH_VERSION,
\r
262 FLS_SST25XX_COMPARE,
\r
266 } Fls_SST25xx_Arc_JobType;
\r
268 /* Spi job state */
\r
272 JOB_READ_STATUS_RESULT,
\r
275 /* Information about a job */
\r
278 Fls_AddressType flsAddr;
\r
280 Job_StateType state;
\r
281 Fls_SST25xx_Arc_JobType mainState;
\r
282 Spi_SequenceType currSeq;
\r
284 } Fls_SST25xx_JobInfoType;
\r
286 #define JOB_SET_STATE(_x,_y) job->state=(_x);job->mainState=(_y)
\r
290 const Fls_ConfigType *config;
\r
292 // Status of driver
\r
293 MemIf_StatusType status;
\r
294 MemIf_JobResultType jobResultType;
\r
295 Fls_SST25xx_Arc_JobType jobType;
\r
297 // Saved information from API calls.
\r
298 Fls_AddressType flsAddr;
\r
300 Fls_LengthType length;
\r
302 // Data containers for EB buffers
\r
303 Spi_DataType ebCmd;
\r
304 Spi_DataType ebReadStatus;
\r
305 Spi_DataType ebFlsAddr[ADDR_LENGTH];
\r
307 // What mode we are in ( normal/fast )
\r
308 MemIf_ModeType mode;
\r
310 // Hold job information
\r
311 Fls_SST25xx_JobInfoType job;
\r
313 } Fls_SST25xx_GlobalType;
\r
315 Fls_SST25xx_GlobalType Fls_SST25xx_Global;
\r
318 #define SPI_TRANSMIT_FUNC(_x) Spi_SyncTransmit(_x)
\r
320 #define SPI_TRANSMIT_FUNC(_x,_y) Fls_SST25xx_AsyncTransmit(_x,_y)
\r
322 Std_ReturnType Fls_SST25xx_AsyncTransmit(Spi_SequenceType Sequence,Fls_SST25xx_JobInfoType *job) {
\r
324 job->currSeq = Sequence;
\r
325 rv = Spi_AsyncTransmit(Sequence);
\r
332 * Convert Fls_AddressType to something used by SPI
\r
334 * @param spiAddr Address to convert to SPI address
\r
335 * @param addr Pointer to the SPI address to be written
\r
338 static void Spi_ConvertToSpiAddr(Spi_DataType *spiAddr, Fls_AddressType addr ) {
\r
340 spiAddr[0] = (addr>>16)&0xff; // MSB first
\r
341 spiAddr[1] = (addr>>8)&0xff;
\r
342 spiAddr[2] = (addr)&0xff;
\r
347 * Get configuration sector information from a flash address
\r
349 * @param addr The address
\r
352 static const Fls_SectorType * Fls_SST25xx_GetSector( Fls_AddressType addr ) {
\r
354 const Fls_SectorType *sector;
\r
356 for (sectorIndex=0; sectorIndex<Fls_SST25xx_Global.config->FlsSectorListSize;sectorIndex++) {
\r
357 sector = &Fls_SST25xx_Global.config->FlsSectorList[sectorIndex];
\r
358 if((((uint32)addr-sector->FlsSectorStartaddress) / sector->FlsSectorSize)<sector->FlsNumberOfSectors){
\r
366 void Fls_SST25xx_Init( const Fls_ConfigType* ConfigPtr ){
\r
368 FLS_VALIDATE_STATUS_BUSY(Fls_SST25xx_Global.status, FLS_INIT_ID);
\r
370 #if ( FLS_SST25XX_VARIANT_PB == STD_ON )
\r
371 VALIDATE( (ConfigPtr != NULL) , FLS_INIT_ID, FLS_E_PARAM_CONFIG );
\r
374 Fls_SST25xx_Global.config = ConfigPtr;
\r
375 Spi_DataType data = 0;
\r
377 Std_ReturnType rv = E_OK;
\r
378 Spi_DataType jedecId[3];
\r
382 // Do some basic testing of configuration data, FLS205
\r
383 VALIDATE_CONFIG(ConfigPtr->FlsMaxReadFastMode != 0 );
\r
384 VALIDATE_CONFIG(ConfigPtr->FlsMaxReadNormalMode != 0 );
\r
385 VALIDATE_CONFIG(ConfigPtr->FlsMaxWriteFastMode != 0 );
\r
386 VALIDATE_CONFIG(ConfigPtr->FlsMaxWriteNormalMode != 0 );
\r
388 VALIDATE_CONFIG(ConfigPtr->FlsAcWrite == NULL ); // NOT supported
\r
389 VALIDATE_CONFIG(ConfigPtr->FlsAcErase == NULL ); // NOT supported
\r
391 // Setup External buffers for jobs and sequences
\r
392 Spi_SetupEB( SPI_CH_FLASH_CMD, &Fls_SST25xx_Global.ebCmd,NULL,sizeof(Fls_SST25xx_Global.ebCmd)/sizeof(Fls_SST25xx_Global.ebCmd));
\r
393 Spi_SetupEB( SPI_CH_FLASH_ADDR, Fls_SST25xx_Global.ebFlsAddr,NULL,sizeof(Fls_SST25xx_Global.ebFlsAddr)/sizeof(Fls_SST25xx_Global.ebFlsAddr[0]));
\r
394 Spi_SetupEB( SPI_CH_FLASH_WREN, NULL,NULL,1);
\r
395 Spi_SetupEB( SPI_CH_FLASH_WRDI, NULL,NULL,1);
\r
396 Spi_SetupEB( SPI_CH_FLASH_WRSR, NULL,NULL,1);
\r
398 /* Check that the JEDEC ID can be read */
\r
399 Spi_SetupEB( SPI_CH_FLASH_DATA, NULL ,jedecId,3);
\r
401 Fls_SST25xx_Global.ebCmd = FLASH_JEDEC_ID;
\r
402 Spi_SyncTransmit(SPI_SEQ_FLASH_CMD_DATA );
\r
404 if( ((jedecId[0]<<16) + (jedecId[1]<<8) + jedecId[2]) != 0xbf2541 ) {
\r
405 LDEBUG_PRINTF("JEDEC: %02x %02x %02x\n",jedecId[0],jedecId[1],jedecId[2]);
\r
409 /* The flash comes locked from factory so it must be unlocked.
\r
410 * The unlock is done in here instead before each write to reduce overhead.
\r
411 * ( The flash is still protected by WREN )
\r
414 /* Unlock flash with sync API. */
\r
415 Spi_SetupEB( SPI_CH_FLASH_DATA, &data, NULL,1);
\r
416 rv = Spi_SyncTransmit(SPI_SEQ_FLASH_WRSR);
\r
419 Spi_SetupEB( SPI_CH_FLASH_DATA, NULL, &Fls_SST25xx_Global.ebReadStatus, 1);
\r
421 Fls_SST25xx_Global.ebCmd = FLASH_RDSR;
\r
422 Spi_SyncTransmit(SPI_SEQ_FLASH_CMD2);
\r
424 } while( (Fls_SST25xx_Global.ebReadStatus != 0) && (timer < TIMER_BUSY_WAIT ));
\r
426 assert(timer!=TIMER_BUSY_WAIT);
\r
428 Fls_SST25xx_Global.status = MEMIF_IDLE;
\r
429 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;
\r
431 // Set currSeq to any sequence we use
\r
432 Fls_SST25xx_Global.job.currSeq = SPI_SEQ_FLASH_WRSR;
\r
436 #if ( FLS_SST25XX_SET_MODE_API == STD_ON )
\r
437 void Fls_SST25xx_SetMode( MemIf_ModeType Mode ){
\r
438 VALIDATE( ( Fls_SST25xx_Global.status != MEMIF_UNINIT ), FLS_SET_MODE_ID, FLS_E_UNINIT );
\r
439 VALIDATE( ( Fls_SST25xx_Global.status != MEMIF_BUSY ), FLS_SET_MODE_ID, FLS_E_BUSY );
\r
441 Fls_SST25xx_Global.mode = Mode;
\r
445 Std_ReturnType Fls_SST25xx_Read ( Fls_AddressType SourceAddress,
\r
446 uint8 *TargetAddressPtr,
\r
447 Fls_LengthType Length )
\r
449 Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;
\r
451 FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_READ_ID, E_NOT_OK);
\r
452 FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_READ_ID, E_NOT_OK);
\r
453 FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(SourceAddress, FLS_READ_ID, E_NOT_OK);
\r
454 FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(SourceAddress, Length, FLS_READ_ID, E_NOT_OK);
\r
455 FLS_VALIDATE_PARAM_DATA_W_RV((void*)TargetAddressPtr, FLS_READ_ID, E_NOT_OK)
\r
457 Fls_SST25xx_Global.status = MEMIF_BUSY;
\r
458 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;
\r
459 Fls_SST25xx_Global.jobType = FLS_SST25XX_READ;
\r
461 if( Fls_SST25xx_Global.mode == MEMIF_MODE_FAST ) {
\r
462 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadFastMode;
\r
464 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadNormalMode;
\r
467 job->flsAddr = SourceAddress;
\r
468 job->targetAddr = TargetAddressPtr;
\r
469 job->left = Length;
\r
471 JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_READ);
\r
477 Std_ReturnType Fls_SST25xx_Erase( Fls_AddressType TargetAddress, Fls_LengthType Length ){
\r
478 Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;
\r
480 FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_ERASE_ID, E_NOT_OK);
\r
481 FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_ERASE_ID, E_NOT_OK);
\r
482 FLS_VALIDATE_PARAM_ADDRESS_SECTOR_W_RV(TargetAddress, FLS_ERASE_ID, E_NOT_OK);
\r
483 FLS_VALIDATE_PARAM_LENGTH_SECTOR_W_RV(TargetAddress, Length, FLS_ERASE_ID, E_NOT_OK);
\r
485 Fls_SST25xx_Global.status = MEMIF_BUSY;
\r
486 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;
\r
487 Fls_SST25xx_Global.jobType = FLS_SST25XX_ERASE;
\r
489 job->flsAddr = TargetAddress;
\r
490 // Not used, so set to illegal value
\r
491 job->targetAddr = (uint8 *)0;
\r
492 job->left = Length;
\r
493 job->chunkSize = Fls_SST25xx_GetSector(TargetAddress)->FlsSectorSize;
\r
495 JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_ERASE);
\r
500 Std_ReturnType Fls_SST25xx_Write( Fls_AddressType TargetAddress, const uint8* SourceAddressPtr, Fls_LengthType Length ){
\r
502 Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;
\r
504 FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_WRITE_ID, E_NOT_OK);
\r
505 FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_WRITE_ID, E_NOT_OK);
\r
506 FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(TargetAddress, FLS_WRITE_ID, E_NOT_OK);
\r
507 FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(TargetAddress, Length, FLS_WRITE_ID, E_NOT_OK);
\r
508 FLS_VALIDATE_PARAM_DATA_W_RV(SourceAddressPtr, FLS_WRITE_ID, E_NOT_OK)
\r
510 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;
\r
511 Fls_SST25xx_Global.status = MEMIF_BUSY;
\r
512 Fls_SST25xx_Global.jobType = FLS_SST25XX_WRITE;
\r
514 if( Fls_SST25xx_Global.mode == MEMIF_MODE_FAST ) {
\r
515 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxWriteFastMode;
\r
517 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxWriteNormalMode;
\r
520 job->flsAddr = TargetAddress;
\r
521 job->targetAddr = (uint8 *)SourceAddressPtr;
\r
522 job->left = Length;
\r
524 JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_WRITE);
\r
530 Std_ReturnType Fls_SST25xx_Compare( Fls_AddressType SourceAddress, uint8 *TargetAddressPtr, Fls_LengthType Length )
\r
532 Fls_SST25xx_JobInfoType *job = &Fls_SST25xx_Global.job;
\r
534 FLS_VALIDATE_STATUS_UNINIT_W_RV(Fls_SST25xx_Global.status, FLS_COMPARE_ID, E_NOT_OK);
\r
535 FLS_VALIDATE_STATUS_BUSY_W_RV(Fls_SST25xx_Global.status, FLS_COMPARE_ID, E_NOT_OK);
\r
536 FLS_VALIDATE_PARAM_ADDRESS_PAGE_W_RV(SourceAddress, FLS_COMPARE_ID, E_NOT_OK);
\r
537 FLS_VALIDATE_PARAM_LENGTH_PAGE_W_RV(SourceAddress, Length, FLS_COMPARE_ID, E_NOT_OK);
\r
538 FLS_VALIDATE_PARAM_DATA_W_RV((void*)SourceAddress,FLS_COMPARE_ID, E_NOT_OK)
\r
540 Fls_SST25xx_Global.status = MEMIF_BUSY;
\r
541 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_PENDING;
\r
542 Fls_SST25xx_Global.jobType = FLS_SST25XX_COMPARE;
\r
544 /* This is a compare job but the compare jobs really issues read in portions
\r
545 * big enough to fit it's static buffers
\r
547 if( Fls_SST25xx_Global.mode == MEMIF_MODE_FAST ) {
\r
548 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadFastMode;
\r
550 job->chunkSize = Fls_SST25xx_Global.config->FlsMaxReadNormalMode;
\r
553 job->flsAddr = SourceAddress;
\r
554 job->targetAddr = TargetAddressPtr;
\r
555 job->left = Length;
\r
557 JOB_SET_STATE(JOB_MAIN,FLS_SST25XX_COMPARE);
\r
563 #if ( FLS_SST25XX_CANCEL_API == STD_ON )
\r
565 /* API NOT SUPPORTED */
\r
567 void Fls_SST25xx_Cancel( void ){
\r
568 if (Fls_SST25xx_Global.config->FlsJobEndNotification!=NULL) Fls_SST25xx_Global.config->FlsJobEndNotification();
\r
570 if (MEMIF_JOB_PENDING==Fls_SST25xx_Global.jobResultType) {
\r
571 Fls_SST25xx_Global.jobResultType=MEMIF_JOB_CANCELLED;
\r
574 Fls_SST25xx_Global.status = MEMIF_IDLE;
\r
579 #if ( FLS_GET_STATUS_API == STD_ON )
\r
580 MemIf_StatusType Fls_SST25xx_GetStatus( void ){
\r
581 return Fls_SST25xx_Global.status;
\r
585 MemIf_JobResultType Fls_SST25xx_GetJobResult( void ){
\r
586 return Fls_SST25xx_Global.jobResultType;
\r
591 * Function that process read/write/erase requests to the SPI
\r
593 * @param job The present job
\r
596 static Spi_SeqResultType Fls_SST25xx_ProcessJob( Fls_SST25xx_JobInfoType *job ) {
\r
597 Spi_SeqResultType rv;
\r
600 /* Check if previous sequence is OK */
\r
601 rv = Spi_GetSequenceResult(job->currSeq);
\r
602 if( rv != SPI_SEQ_OK ) {
\r
606 rv = SPI_SEQ_PENDING;
\r
609 switch(job->state ) {
\r
610 case JOB_READ_STATUS:
\r
611 DEBUG(DEBUG_LOW,"%s: READ_STATUS\n",MODULE_NAME);
\r
612 /* Check status from erase cmd, read status from flash */
\r
613 Spi_SetupEB( SPI_CH_FLASH_DATA, NULL, &Fls_SST25xx_Global.ebReadStatus, 1);
\r
614 Fls_SST25xx_Global.ebCmd = FLASH_RDSR;
\r
615 if( SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_CMD2,job ) != E_OK ) {
\r
618 SET_STATE(1,JOB_READ_STATUS_RESULT);
\r
621 case JOB_READ_STATUS_RESULT:
\r
622 DEBUG(DEBUG_LOW,"%s: READ_STATUS_RESULT\n",MODULE_NAME);
\r
623 if( Fls_SST25xx_Global.ebReadStatus&1 ) {
\r
624 SET_STATE(0,JOB_READ_STATUS);
\r
626 SET_STATE(0,JOB_MAIN);
\r
631 if( job->left != 0 ) {
\r
632 if( job->left <= job->chunkSize ) {
\r
633 job->chunkSize = job->left;
\r
636 Spi_ConvertToSpiAddr(Fls_SST25xx_Global.ebFlsAddr,job->flsAddr);
\r
638 switch(job->mainState) {
\r
639 case FLS_SST25XX_ERASE:
\r
640 DEBUG(DEBUG_LOW,"%s: Erase 4K s:%04x\n",MODULE_NAME,job->flsAddr);
\r
641 Fls_SST25xx_Global.ebCmd = FLASH_ERASE_4K;
\r
642 SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_WRITE,job );
\r
645 case FLS_SST25XX_READ:
\r
646 case FLS_SST25XX_COMPARE:
\r
647 DEBUG(DEBUG_LOW,"%s: READ s:%04x d:%04x l:%04x\n",MODULE_NAME,job->flsAddr, job->targetAddr, job->left);
\r
648 Fls_SST25xx_Global.ebCmd = FLASH_READ_25;
\r
649 Spi_SetupEB( SPI_CH_FLASH_DATA, NULL ,job->targetAddr,job->chunkSize);
\r
650 SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_READ,job );
\r
653 case FLS_SST25XX_WRITE:
\r
654 DEBUG(DEBUG_LOW,"%s: WRITE d:%04x s:%04x first data:%02x\n",MODULE_NAME,job->flsAddr,job->targetAddr,*job->targetAddr);
\r
655 Fls_SST25xx_Global.ebCmd = FLASH_BYTE_WRITE;
\r
656 Spi_ConvertToSpiAddr(Fls_SST25xx_Global.ebFlsAddr,job->flsAddr);
\r
657 Spi_SetupEB( SPI_CH_FLASH_DATA, job->targetAddr, NULL, job->chunkSize);
\r
658 SPI_TRANSMIT_FUNC(SPI_SEQ_FLASH_WRITE,job );
\r
666 job->flsAddr += job->chunkSize;
\r
667 job->targetAddr += job->chunkSize;
\r
668 job->left -= job->chunkSize;
\r
669 SET_STATE(1,JOB_READ_STATUS);
\r
672 /* We are done :) */
\r
673 SET_STATE(1,JOB_MAIN);
\r
674 job->mainState = FLS_SST25XX_NONE;
\r
689 #define CMP_BUFF_SIZE SPI_EB_MAX_LENGTH
\r
691 void Fls_SST25xx_MainFunction( void )
\r
693 Spi_SeqResultType jobResult;
\r
695 if( Fls_SST25xx_Global.jobResultType == MEMIF_JOB_PENDING ) {
\r
696 switch (Fls_SST25xx_Global.jobType) {
\r
697 case FLS_SST25XX_COMPARE: {
\r
698 static Fls_SST25xx_JobInfoType readJob;
\r
699 static uint8 Fls_SST25xx_CompareBuffer[SPI_EB_MAX_LENGTH];
\r
700 Fls_SST25xx_JobInfoType *gJob = &Fls_SST25xx_Global.job;
\r
701 static _Bool firstTime = 1;
\r
702 static uint32 readSize;
\r
704 /* Compare jobs must use a local buffer to hold one portion
\r
705 * of the job. Since Fls_SST25xx_ProcessJob() also manipulates the
\r
706 * job structure we need to create a new local job each time.
\r
707 * The global job updates is updated for each process job.
\r
710 if (firstTime == 1) {
\r
713 if ( gJob->left <= CMP_BUFF_SIZE ) {
\r
714 readSize = gJob->left;
\r
716 readSize = CMP_BUFF_SIZE;
\r
718 readJob.left = readSize;
\r
719 readJob.targetAddr = Fls_SST25xx_CompareBuffer;
\r
723 jobResult = Fls_SST25xx_ProcessJob(&readJob);
\r
725 if( jobResult == SPI_SEQ_PENDING ) {
\r
727 } else if( jobResult == SPI_SEQ_OK ) {
\r
729 if( memcmp(Fls_SST25xx_CompareBuffer,gJob->targetAddr, readSize) != 0 ) {
\r
730 #if defined(USE_DEM)
\r
731 Dem_ReportErrorStatus(FLS_E_COMPARE_FAILED, DEM_EVENT_STATUS_FAILED);
\r
733 FEE_JOB_ERROR_NOTIFICATION();
\r
736 // Update the global comare job
\r
737 gJob->targetAddr += readSize;
\r
738 gJob->flsAddr += readSize;
\r
739 gJob->left -= readSize;
\r
741 // Check if we are done
\r
742 if( gJob->left == 0 ) {
\r
743 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_OK;
\r
744 Fls_SST25xx_Global.jobType = FLS_SST25XX_NONE;
\r
745 Fls_SST25xx_Global.status = MEMIF_IDLE;
\r
746 FEE_JOB_END_NOTIFICATION();
\r
750 // Calculate new readSize
\r
751 if ( gJob->left <= CMP_BUFF_SIZE ) {
\r
752 readSize = gJob->left;
\r
754 readSize = CMP_BUFF_SIZE;
\r
757 // Update the readjob for next session
\r
759 readJob.left = readSize;
\r
760 readJob.targetAddr = Fls_SST25xx_CompareBuffer;
\r
762 // all other cases are bad
\r
764 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_FAILED;
\r
765 Fls_SST25xx_Global.jobType = FLS_SST25XX_NONE;
\r
766 Fls_SST25xx_Global.status = MEMIF_IDLE;
\r
768 #if defined(USE_DEM)
\r
769 Dem_ReportErrorStatus(FLS_E_COMPARE_FAILED, DEM_EVENT_STATUS_FAILED);
\r
771 FEE_JOB_ERROR_NOTIFICATION();
\r
776 case FLS_SST25XX_ERASE:
\r
777 case FLS_SST25XX_READ:
\r
778 case FLS_SST25XX_WRITE:
\r
780 jobResult = Fls_SST25xx_ProcessJob(&Fls_SST25xx_Global.job);
\r
782 if( jobResult == SPI_SEQ_OK ) {
\r
784 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_OK;
\r
785 Fls_SST25xx_Global.jobType = FLS_SST25XX_NONE;
\r
786 Fls_SST25xx_Global.status = MEMIF_IDLE;
\r
787 FEE_JOB_END_NOTIFICATION();
\r
788 } else if( jobResult == SPI_SEQ_PENDING ) {
\r
789 /* Busy, Do nothing */
\r
792 Fls_SST25xx_Global.jobResultType = MEMIF_JOB_FAILED;
\r
794 switch(Fls_SST25xx_Global.jobType) {
\r
795 case FLS_SST25XX_ERASE:
\r
796 #if defined(USE_DEM)
\r
797 Dem_ReportErrorStatus(FLS_E_ERASED_FAILED, DEM_EVENT_STATUS_FAILED);
\r
800 case FLS_SST25XX_READ:
\r
801 #if defined(USE_DEM)
\r
802 Dem_ReportErrorStatus(FLS_E_READ_FAILED, DEM_EVENT_STATUS_FAILED);
\r
805 case FLS_SST25XX_WRITE:
\r
806 #if defined(USE_DEM)
\r
807 Dem_ReportErrorStatus(FLS_E_WRITE_FAILED, DEM_EVENT_STATUS_FAILED);
\r
814 FEE_JOB_ERROR_NOTIFICATION();
\r
817 case FLS_SST25XX_NONE:
\r
825 #if ( FLS_SST25XX_VERSION_INFO_API == STD_ON )
\r
826 void Fls_SST25XX_GetVersionInfo( Std_VersionInfoType *VersioninfoPtr )
\r
828 memcpy(VersioninfoPtr, &Fls_SST25XX_VersionInfo, sizeof(Std_VersionInfoType));
\r