/**************************************************************************************
** sram.c  64kByte Speicherchip über 2 8bit shift register adressiert
**
** 27.08.2011 li test mit delays ok
** 29.08.2011 li neue pz_soll routine
** 22.02.2013 li Optimierungen
*/

#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include "basis.h"
#include "sram.h"

void set_addr( unsigned int addr);
unsigned char pz_soll( unsigned int adr);
                                            // sram Test used
unsigned char sram_read_nad( void );
void sram_write_nad( unsigned char value );

/***************************************************************
**  Ports frei schalten
*/
void sram_init(void)
{
   SRAM_CNTL_DDR = SRAM_SHIFT_CL+SRAM_SHIFT_OE+SRAM_SHIFT_DA+SRAM_MEM_WR+SRAM_MEM_OE+SRAM_MEM_CE;

   SRAM_CNTLPORT |= SRAM_MEM_WR;      // inaktiv
   SRAM_CNTLPORT |= SRAM_MEM_OE;      // inaktiv
   SRAM_CNTLPORT |= SRAM_MEM_CE;      // inaktiv

   SRAM_CNTLPORT |= SRAM_SHIFT_CL;    // Clock auf 1 setzen
   SRAM_CNTLPORT &= ~SRAM_SHIFT_OE;   // output enable auf 0 setzen
}



/***************************************************************
**  read Datum von addresse
**  20.2.2013 li bei 16Mhz Zugriffszeit ca. 13,5µsek
*/
unsigned char sram_read( unsigned int addr )
{
   set_addr(addr);
   return sram_read_nad();
}



/***************************************************************
**  read Datum, adresse im shift register
*/
unsigned char sram_read_nad( void )
{
   unsigned char data;

   SRAM_CNTLPORT |= SRAM_SHIFT_OE;                 // Adresse anschalten
   SRAM_DATA_DDR = 0;     // auf input
   SRAM_DATAPORT = 255;   // interne pullups
   SRAM_CNTLPORT &= ~(SRAM_MEM_OE+SRAM_MEM_CE);    // output enable und CE
   asm("nop");   // 62,5nsec bei 16 MHz
   data = SRAM_DATA_IN;                            // Daten Byte holen
   SRAM_CNTLPORT |= SRAM_MEM_OE + SRAM_MEM_CE;     // inaktiv
   SRAM_CNTLPORT &= ~SRAM_SHIFT_OE;                // Adr. Register output enable auf 0 setzen
   return data;
}



/***************************************************************
**  write datum an adresse
*/
void sram_write( unsigned int addr, unsigned char value )
{
   set_addr(addr);
   sram_write_nad( value );
}



/***************************************************************
**  write datum, adresse im shift register
*/
void sram_write_nad( unsigned char value )
{
   SRAM_CNTLPORT |= SRAM_SHIFT_OE;          // Adresse anschalten
   SRAM_DATA_DDR = 255;                     // auf output
   SRAM_DATAPORT = value;                   // datenbyte
   SRAM_CNTLPORT &= ~(SRAM_MEM_CE);         // selekt sram
   asm("nop");   // 62,5nsec bei 16 MHz
   asm("nop");   // 62,5nsec bei 16 MHz
   SRAM_CNTLPORT &= ~(SRAM_MEM_WR);         // write strobe aktiv
   SRAM_CNTLPORT |= SRAM_MEM_WR ;           // inaktiv
   SRAM_DATA_DDR = 0;                       // auf input
   SRAM_CNTLPORT |= SRAM_MEM_CE;            // inaktiv
   SRAM_CNTLPORT &= ~SRAM_SHIFT_OE;         // output enable auf 0 setzen
}



/***************************************************************
**  16 Bit SRAM Adresse ins Shift Register
*/
void set_addr( unsigned int addr)
{
   unsigned char n=0, temp;

   temp = (unsigned char)(addr >> 8);       // high A8-A15

   do
   {
      if ( temp & 0x80 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x40 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x20 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x10 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x08 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x04 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x02 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      if ( temp & 0x01 )                    // Bit high or low ?
         SRAM_CNTLPORT |= SRAM_SHIFT_DA;    // DATA auf 1
      else
         SRAM_CNTLPORT &= ~SRAM_SHIFT_DA;   // DATA auf 0
      SRAM_CNTLPORT &= ~SRAM_SHIFT_CL;      // CP auf 0 = clock aktiv
      SRAM_CNTLPORT |= SRAM_SHIFT_CL;       // CP auf 1 setzen

      temp = (unsigned char)addr & 0x00FF;  // low A0-A7

   } while ( ++n < 2);
}



/*****************************************************************************
** Speicher test
** starten bei 0 bis max ( max von 256 bis overflow )
** erst schreiben und sofort prüfen
** dann prüfen ab 0 bis max, wenn fehler stop
** 20.2.2013 verbesserte Version
*/
#if TEST_SRAM
unsigned char sram_testmem( S_SRAM *tsram, volatile unsigned int *ticks )
#else
unsigned char sram_testmem( S_SRAM *tsram)
#endif
{
   unsigned int adr=0;
   unsigned char s1;
   unsigned char r1;
#if TEST_SRAM
   unsigned int tstart = *ticks;
#endif
   for (;;)                          // write Loop
   {
      set_addr(adr);                 // set

      sram_write_nad( 0x00 );        // alles auf 0 check
      r1 = sram_read_nad();
      if ( r1 != 0x00 )
      {
         tsram->adr = adr;
         tsram->soll = 0x00;
         tsram->ist = r1;
         tsram->flag = SRAM_WRITE_ERROR;
         return 0;
      }

      sram_write_nad( 0xff );        // alles auf 1 check
      r1 = sram_read_nad();
      if ( r1 != 0xff )
      {
         tsram->adr = adr;
         tsram->soll = 0xff;
         tsram->ist = r1;
         tsram->flag =  SRAM_WRITE_ERROR;
         return 0;
      }

      s1 = pz_soll( adr );
      sram_write( adr, s1 );
      r1 = sram_read( adr);
      if ( s1 != r1  )
      {
         tsram->adr = adr;
         tsram->soll = s1;
         tsram->ist = r1;
         tsram->flag =  SRAM_WRITE_ERROR;
         return 0;
      }
      adr++;
      if ( adr == 0 )
         break;
   }
#if TEST_SRAM
   tsram->ticks_write = *ticks - tstart ;
   tstart = *ticks;
#endif
   adr = 0;
   for (;;)                          // read Loop
   {
      r1 = sram_read( adr );
      s1 = pz_soll(adr);

      if ( s1 != r1  )
      {
         tsram->adr = adr;
         tsram->soll = s1;
         tsram->ist = r1;
         tsram->flag = SRAM_READ_ERROR;
         return 0;
      }
      adr++;
      if ( adr == 0)
         break;
   }
   tsram->flag = SRAM_TEST_OK;
#if TEST_SRAM
   tsram->ticks_read = *ticks - tstart ;
   tstart = *ticks;
#endif
   return 1;
}



/*****************************************************************************
** Prüfzahl um Speicher Fehladressierung
*/
unsigned char pz_soll( unsigned int adr)
{
   unsigned char e,n;

   e = adr & 0xFF;
   n = (adr >> 8) & 0xFF;
   e += n;

   return e;
}
