1 /* -------------------------------- Arctic Core ------------------------------
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
6 * This source code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by the
8 * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * -------------------------------- Arctic Core ------------------------------*/
25 * IMPLEMENTATION NOTES
26 * - The SPI implementation only supports 64 bytes in one go so this is
27 * a limitation for the EEP driver also.
28 * - The specification if SPI functions should be blocking or not. For now
29 * the driver uses blocking SPI communication.
39 * Only EEP_WRITE_CYCLE_REDUCTION = STD_OFF is supported
42 * MEMIF_COMPARE_UNEQUAL does not exist in the MemIf specification 1.2.1(rel 3.0 )
43 * So, it's not supported. It returns MEMIF_JOB_FAILED instead.
46 * EepJobCallCycle not used
47 * We are not using interrupts so EEP_USE_INTERRUPTS must be STD_OFF
61 #define MODULE_NAME "/driver/Eep"
63 // Define if you to check if the E2 seems sane at init..
67 /* The width in bytes used by this eeprom */
70 /* Helper macro for the process function */
71 #define SET_STATE(_done,_state) done=(_done);job->state=(_state)
73 #if ( EEP_DEV_ERROR_DETECT == STD_ON ) // Report DEV errors
74 #define VALIDATE(_exp,_api,_err ) \
76 Det_ReportError(MODULE_ID_GPT,0,_api,_err); \
80 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \
82 Det_ReportError(MODULE_ID_GPT,0,_api,_err); \
86 #define VALID_CHANNEL(_ch) ( Gpt_Global.configured & (1<<(_ch)) )
88 #else // Validate but do not report
89 #define VALIDATE(_exp,_api,_err )\
93 #define VALIDATE_W_RV(_exp,_api,_err,_rv )\
99 #if ( EEP_DEV_ERROR_DETECT == STD_ON )
100 #define VALIDATE_CONFIG(_x) assert(_x)
101 #define DET_REPORTERROR(_x,_y,_z,_q) Det_ReportError(MODULE_ID_EEP, _y, _z, _q)
103 #define VALIDATE_CONFIG(_x)
104 #define DET_REPORTERROR(_x,_y,_z,_q)
107 #define EEP_JOB_END_NOTIFICATION() \
108 if (Eep_Global.config->Eep_JobEndNotification!=NULL) { \
109 Eep_Global.config->Eep_JobEndNotification(); \
112 #define EEP_JOB_ERROR_NOTIFICATION() \
113 if (Eep_Global.config->Eep_JobErrorNotification!=NULL) { \
114 Eep_Global.config->Eep_JobErrorNotification(); \
130 JOB_READ_STATUS_RESULT,
133 /* Information about a job */
136 Eep_AddressType eepAddr;
139 Eep_Arc_JobType mainState;
140 Spi_SequenceType currSeq;
144 #define JOB_SET_STATE(_x,_y) job->state=(_x);job->mainState=(_y)
148 * Holds all global information that is needed by the driver
153 const Eep_ConfigType *config;
156 MemIf_StatusType status;
157 MemIf_JobResultType jobResultType;
158 Eep_Arc_JobType jobType;
160 // Saved information from API calls.
161 MemIf_AddressType e2Addr;
163 MemIf_LengthType length;
165 // Data containers for EB buffers
167 Spi_DataType ebReadStatus;
168 Spi_DataType ebE2Addr[ADDR_LENGTH];
169 // What mode we are in ( normal/fast )
172 // Hold job information
178 #define SPI_TRANSMIT_FUNC(_x) Spi_SyncTransmit(_x)
180 #define SPI_TRANSMIT_FUNC(_x,_y) Eep_AsyncTransmit(_x,_y)
182 Std_ReturnType Eep_AsyncTransmit(Spi_SequenceType Sequence,Eep_JobInfoType *job) {
184 job->currSeq = Sequence;
185 rv = Spi_AsyncTransmit(Sequence);
190 #define CFG_P() Eep_Global.config
192 Eep_GlobalType Eep_Global;
195 * Converts Eep_AddressType to one that can be read by SPI( Spi_DataType )
197 * @param spiAddr Pointer to an address were the result is written.
198 * @param eepAddr The Eep address to convert
200 static void Spi_ConvertToSpiAddr(Spi_DataType *spiAddr, Eep_AddressType eepAddr ) {
201 spiAddr[1] = (eepAddr)&0xff;
202 spiAddr[0] = (eepAddr>>8)&0xff;
206 #if defined(CHECK_SANE)
207 static void Eep_WREN( void ) {
208 Eep_Global.ebCmd = E2_WREN;
209 Spi_SetupEB( CFG_P()->EepDataChannel, NULL ,NULL ,1);
210 Spi_SyncTransmit(CFG_P()->EepCmdSequence);
213 static void Eep_WRDI( void ) {
214 Eep_Global.ebCmd = E2_WRDI;
215 Spi_SetupEB( CFG_P()->EepDataChannel, NULL ,NULL ,1);
216 Spi_SyncTransmit(CFG_P()->EepCmdSequence);
220 static uint8 Eep_ReadStatusReg( void ) {
221 Spi_SetupEB( CFG_P()->EepDataChannel, NULL, &Eep_Global.ebReadStatus, 1);
222 Eep_Global.ebCmd = E2_RDSR;
223 Spi_SyncTransmit(CFG_P()->EepCmd2Sequence);
224 return Eep_Global.ebReadStatus;
228 void Eep_Init( const Eep_ConfigType* ConfigPtr ){
229 VALIDATE( (ConfigPtr != NULL) , EEP_INIT_ID, EEP_E_PARAM_CONFIG );
230 Eep_Global.config = ConfigPtr;
232 Spi_SetupEB( CFG_P()->EepCmdChannel, &Eep_Global.ebCmd,NULL,sizeof(Eep_Global.ebCmd)/sizeof(Eep_Global.ebCmd));
233 Spi_SetupEB( CFG_P()->EepAddrChannel, Eep_Global.ebE2Addr,NULL,sizeof(Eep_Global.ebE2Addr)/sizeof(Eep_Global.ebE2Addr[0]));
234 Spi_SetupEB( CFG_P()->EepWrenChannel, NULL,NULL,1);
236 #if defined( CHECK_SANE )
240 // - check if 1 by reading with RDSR,
242 // - check if 0 by reading with RDSR,
245 if( (Eep_ReadStatusReg() & 0x2) == 0 ) {
249 if( (Eep_ReadStatusReg() & 0x2) ) {
255 Eep_Global.status = MEMIF_IDLE;
256 Eep_Global.jobResultType = MEMIF_JOB_OK;
261 void Eep_SetMode( MemIf_ModeType Mode ){
262 VALIDATE( ( Eep_Global.status != MEMIF_UNINIT ), EEP_SETMODE_ID, EEP_E_UNINIT );
263 VALIDATE( ( Eep_Global.status != MEMIF_BUSY ), EEP_SETMODE_ID, EEP_E_BUSY );
265 Eep_Global.mode = Mode;
268 Std_ReturnType Eep_Read ( Eep_AddressType EepromAddress,
269 uint8 *TargetAddressPtr,
270 Eep_LengthType Length )
272 Eep_JobInfoType *job = &Eep_Global.job;
274 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_UNINIT ), EEP_READ_ID, EEP_E_UNINIT, E_NOT_OK );
275 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_BUSY ), EEP_READ_ID, EEP_E_BUSY, E_NOT_OK );
276 VALIDATE_W_RV( ( TargetAddressPtr != NULL ) , EEP_READ_ID, EEP_E_PARAM_DATA, E_NOT_OK );
277 VALIDATE_W_RV( ( (EepromAddress) < (Eep_Global.config->EepSize) ) , EEP_READ_ID, EEP_E_PARAM_ADDRESS, E_NOT_OK );
278 VALIDATE_W_RV( ( (Eep_Global.config->EepSize - EepromAddress) >= Length ) , EEP_READ_ID, EEP_E_PARAM_LENGTH, E_NOT_OK );
280 Eep_Global.status = MEMIF_BUSY;
281 Eep_Global.jobResultType = MEMIF_JOB_PENDING;
282 Eep_Global.jobType = EEP_READ;
284 if( Eep_Global.mode == MEMIF_MODE_FAST ) {
285 job->chunkSize = Eep_Global.config->EepFastReadBlockSize;
287 job->chunkSize = Eep_Global.config->EepNormalReadBlockSize;
290 job->eepAddr = EepromAddress;
291 job->targetAddr = TargetAddressPtr;
294 JOB_SET_STATE(JOB_MAIN,EEP_READ);
299 Std_ReturnType Eep_Erase( Eep_AddressType TargetAddress, Eep_LengthType Length ){
300 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_UNINIT ), EEP_ERASE_ID, EEP_E_UNINIT, E_NOT_OK );
301 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_BUSY ), EEP_ERASE_ID, EEP_E_BUSY, E_NOT_OK );
302 VALIDATE_W_RV( ( (TargetAddress) < (Eep_Global.config->EepSize) ) , EEP_ERASE_ID, EEP_E_PARAM_ADDRESS, E_NOT_OK );
303 VALIDATE_W_RV( ( (Eep_Global.config->EepSize - TargetAddress) >= Length ) , EEP_ERASE_ID, EEP_E_PARAM_LENGTH, E_NOT_OK );
305 /* TODO : NOT IMPLEMENTED
306 * ( Since this E2 do not have erase )
308 Std_ReturnType rv = E_NOT_OK;
309 Eep_Global.status = MEMIF_BUSY;
310 Eep_Global.status = MEMIF_IDLE;
314 Std_ReturnType Eep_Write( Eep_AddressType EepromAddress, const uint8* DataBufferPtr, Eep_LengthType Length ){
315 Eep_JobInfoType *job = &Eep_Global.job;
317 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_UNINIT ), EEP_WRITE_ID, EEP_E_UNINIT, E_NOT_OK );
318 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_BUSY ), EEP_WRITE_ID, EEP_E_BUSY, E_NOT_OK );
319 VALIDATE_W_RV( ( DataBufferPtr != NULL ) , EEP_WRITE_ID, EEP_E_PARAM_DATA, E_NOT_OK );
320 VALIDATE_W_RV( ( (EepromAddress) < (Eep_Global.config->EepSize) ) , EEP_WRITE_ID, EEP_E_PARAM_ADDRESS, E_NOT_OK );
321 VALIDATE_W_RV( ( Length <= (Eep_Global.config->EepSize - EepromAddress) ) , EEP_WRITE_ID, EEP_E_PARAM_LENGTH, E_NOT_OK );
323 Eep_Global.jobResultType = MEMIF_JOB_PENDING;
324 Eep_Global.status = MEMIF_BUSY;
325 Eep_Global.jobType = EEP_WRITE;
327 if( Eep_Global.mode == MEMIF_MODE_FAST ) {
328 job->chunkSize = Eep_Global.config->EepFastWriteBlockSize;
330 job->chunkSize = Eep_Global.config->EepNormalWriteBlockSize;
333 job->eepAddr = EepromAddress;
334 job->targetAddr = (uint8 *)DataBufferPtr;
337 JOB_SET_STATE(JOB_MAIN,EEP_WRITE);
343 Std_ReturnType Eep_Compare( Eep_AddressType EepromAddress, uint8 *TargetAddressPtr, Eep_LengthType Length )
345 Eep_JobInfoType *job = &Eep_Global.job;
347 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_UNINIT ), EEP_COMPARE_ID, EEP_E_UNINIT, E_NOT_OK );
348 VALIDATE_W_RV( ( Eep_Global.status != MEMIF_BUSY ), EEP_COMPARE_ID, EEP_E_BUSY, E_NOT_OK );
349 VALIDATE_W_RV( ( TargetAddressPtr != NULL ) , EEP_COMPARE_ID, EEP_E_PARAM_DATA, E_NOT_OK );
350 VALIDATE_W_RV( ( (EepromAddress) < (Eep_Global.config->EepSize) ) , EEP_COMPARE_ID, EEP_E_PARAM_ADDRESS, E_NOT_OK );
351 VALIDATE_W_RV( ( (Eep_Global.config->EepSize - EepromAddress) >= Length ) , EEP_COMPARE_ID, EEP_E_PARAM_LENGTH, E_NOT_OK );
353 Eep_Global.status = MEMIF_BUSY;
354 Eep_Global.jobResultType = MEMIF_JOB_PENDING;
355 Eep_Global.jobType = EEP_COMPARE;
357 /* This is a compare job but the compare jobs really issues read in portions
358 * big enough to fit it's static buffers
360 if( Eep_Global.mode == MEMIF_MODE_FAST ) {
361 job->chunkSize = Eep_Global.config->EepFastReadBlockSize;
363 job->chunkSize = Eep_Global.config->EepNormalReadBlockSize;
366 job->eepAddr = EepromAddress;
367 job->targetAddr = TargetAddressPtr;
370 JOB_SET_STATE(JOB_MAIN,EEP_COMPARE);
376 void Eep_Cancel( void ){
377 EEP_JOB_END_NOTIFICATION();
379 if (MEMIF_JOB_PENDING==Eep_Global.jobResultType) {
380 Eep_Global.jobResultType=MEMIF_JOB_CANCELLED;
383 Eep_Global.status = MEMIF_IDLE;
386 MemIf_StatusType Eep_GetStatus( void ){
387 return Eep_Global.status;
390 MemIf_JobResultType Eep_GetJobResult( void ){
391 return Eep_Global.jobResultType;
396 * Function that process read/write/erase requests to the SPI
398 * @param job The present job
401 static Spi_SeqResultType Eep_ProcessJob( Eep_JobInfoType *job ) {
402 Spi_SeqResultType rv;
405 /* Check if previous sequence is OK */
406 rv = Spi_GetSequenceResult(job->currSeq);
407 if( rv != SPI_SEQ_OK ) {
411 rv = SPI_SEQ_PENDING;
414 switch(job->state ) {
415 case JOB_READ_STATUS:
416 DEBUG(DEBUG_LOW,"%s: READ_STATUS\n",MODULE_NAME);
417 /* Check status from erase cmd, read status from flash */
418 Spi_SetupEB( CFG_P()->EepDataChannel, NULL, &Eep_Global.ebReadStatus, 1);
419 Eep_Global.ebCmd = E2_RDSR;
420 if( SPI_TRANSMIT_FUNC(CFG_P()->EepCmd2Sequence,job ) != E_OK ) {
423 SET_STATE(1,JOB_READ_STATUS_RESULT);
426 case JOB_READ_STATUS_RESULT:
427 DEBUG(DEBUG_LOW,"%s: READ_STATUS_RESULT\n",MODULE_NAME);
428 if( Eep_Global.ebReadStatus&1 ) {
429 SET_STATE(0,JOB_READ_STATUS);
431 SET_STATE(0,JOB_MAIN);
436 if( job->left != 0 ) {
437 if( job->left <= job->chunkSize ) {
438 job->chunkSize = job->left;
441 Spi_ConvertToSpiAddr(Eep_Global.ebE2Addr,job->eepAddr);
443 switch(job->mainState) {
450 DEBUG(DEBUG_LOW,"%s: READ s:%04x d:%04x l:%04x\n",MODULE_NAME,job->eepAddr, job->targetAddr, job->left);
451 Eep_Global.ebCmd = E2_READ;
452 Spi_SetupEB( CFG_P()->EepDataChannel, NULL ,job->targetAddr,job->chunkSize);
453 SPI_TRANSMIT_FUNC(CFG_P()->EepReadSequence,job );
457 DEBUG(DEBUG_LOW,"%s: WRITE d:%04x s:%04x first data:%02x\n",MODULE_NAME,job->eepAddr,job->targetAddr,*job->targetAddr);
458 Eep_Global.ebCmd = E2_WRITE;
459 Spi_ConvertToSpiAddr(Eep_Global.ebE2Addr,job->eepAddr);
460 Spi_SetupEB( CFG_P()->EepDataChannel, job->targetAddr, NULL, job->chunkSize);
461 SPI_TRANSMIT_FUNC(CFG_P()->EepWriteSequence,job );
469 job->eepAddr += job->chunkSize;
470 job->targetAddr += job->chunkSize;
471 job->left -= job->chunkSize;
472 SET_STATE(1,JOB_READ_STATUS);
476 SET_STATE(1,JOB_MAIN);
477 job->mainState = EEP_NONE;
491 #define CMP_BUFF_SIZE SPI_EB_MAX_LENGTH
493 void Eep_MainFunction( void )
495 Spi_SeqResultType jobResult;
497 if( Eep_Global.jobResultType == MEMIF_JOB_PENDING ) {
498 switch (Eep_Global.jobType) {
500 static Eep_JobInfoType readJob;
501 static uint8 Eep_CompareBuffer[SPI_EB_MAX_LENGTH];
502 Eep_JobInfoType *gJob = &Eep_Global.job;
503 static _Bool firstTime = 1;
504 static uint32 readSize;
506 /* Compare jobs must use a local buffer to hold one portion
507 * of the job. Since Eep_ProcessJob() also manipulates the
508 * job structure we need to create a new local job each time.
509 * The global job updates is updated for each process job.
512 if (firstTime == 1) {
515 if ( gJob->left <= CMP_BUFF_SIZE ) {
516 readSize = gJob->left;
518 readSize = CMP_BUFF_SIZE;
520 readJob.left = readSize;
521 readJob.targetAddr = Eep_CompareBuffer;
525 jobResult = Eep_ProcessJob(&readJob);
527 if( jobResult == SPI_SEQ_PENDING ) {
529 } else if( jobResult == SPI_SEQ_OK ) {
531 if( memcmp(Eep_CompareBuffer,gJob->targetAddr, readSize) != 0 ) {
532 DET_REPORTERROR(MODULE_ID_EEP,0, 0x9, MEMIF_JOB_FAILED );
533 EEP_JOB_ERROR_NOTIFICATION();
536 // Update the global comare job
537 gJob->targetAddr += readSize;
538 gJob->eepAddr += readSize;
539 gJob->left -= readSize;
541 // Check if we are done
542 if( gJob->left == 0 ) {
543 Eep_Global.jobResultType = MEMIF_JOB_OK;
544 Eep_Global.jobType = EEP_NONE;
545 Eep_Global.status = MEMIF_IDLE;
546 EEP_JOB_END_NOTIFICATION();
550 // Calculate new readSize
551 if ( gJob->left <= CMP_BUFF_SIZE ) {
552 readSize = gJob->left;
554 readSize = CMP_BUFF_SIZE;
557 // Update the readjob for next session
559 readJob.left = readSize;
560 readJob.targetAddr = Eep_CompareBuffer;
562 // all other cases are bad
564 Eep_Global.jobResultType = MEMIF_JOB_FAILED;
565 Eep_Global.jobType = EEP_NONE;
566 Eep_Global.status = MEMIF_IDLE;
568 DET_REPORTERROR(MODULE_ID_EEP,0, 0x9, MEMIF_JOB_FAILED );
569 EEP_JOB_ERROR_NOTIFICATION();
578 jobResult = Eep_ProcessJob(&Eep_Global.job);
580 if( jobResult == SPI_SEQ_OK ) {
582 Eep_Global.jobResultType = MEMIF_JOB_OK;
583 Eep_Global.jobType = EEP_NONE;
584 Eep_Global.status = MEMIF_IDLE;
585 EEP_JOB_END_NOTIFICATION();
586 } else if( jobResult == SPI_SEQ_PENDING ) {
587 /* Busy, Do nothing */
590 Eep_Global.jobResultType = MEMIF_JOB_FAILED;
591 Eep_Global.jobType = EEP_NONE;
592 Eep_Global.status = MEMIF_IDLE;
594 switch(Eep_Global.jobType) {
596 DET_REPORTERROR(MODULE_ID_EEP,0, 0x9, MEMIF_JOB_FAILED );
599 DET_REPORTERROR(MODULE_ID_EEP,0, 0x9, MEMIF_JOB_FAILED );
602 DET_REPORTERROR(MODULE_ID_EEP,0, 0x9, MEMIF_JOB_FAILED );
608 EEP_JOB_ERROR_NOTIFICATION();