Introduction to the SRAM on the BlueberryE Uno335

This is a short tutorial explaining how to use the Serial SRAM of the Uno335. This tutorial uses the Arduino SPI Library to communicate with the SRAM. BlueberryE will also provide a library which uses as Stack data structure to store data in the SRAM: see our tutorial Using the BB_SramStack Library to access the Serial SRAM of the BlueberryE Uno335.

Content

  • The Serial SRAM
  • Jumper settings
  • Example sketch

The Serial SRAM

The BlueberryE Uno335 has a serially assessed Static Random Access Memory (SRAM) with a capacity of 521Kbit on board. The data are organized as 64K data units with 8 bits each. 16-bit addresses are used for selecting specific data units. The device is accessed by a serial interface that is SPI-compatible. Thus, there are 4 pins which are used for the communication with the ATmega328P:

SRAM pin SRAM pin mode ATmega pin ATmega pin mode Pin function
_CS input A3 output Chip select (active low)
SO output MISO (pin 12) input data from SRAM to ATmega328P
SI input MOSI (pin 11) input data from ATmega328P to SRAM
SCK input SCK (pin 13) output Clock for SPI communication

The programme has to make sure that the ATmega328P pins are defined correctly (See Example sketch). On the Uno335, the SRAM gets a supply voltage of 3.3V if jumper JP3 is set. Additionally, the pin A3 has to be connected to the _CS pin of the SRAM using jumper JP12 (see Jumper Settings).

The SRAM has a 8-bit status register, which is used to control the operation mode of the SRAM. Bit 0 has to be set to 1. Bit 1 - Bit 5 are reserved. Bit 6 and Bit 7 define the operation mode. We will explain only Byte Mode and Virtual Chip Mode:

Bit 7 Bit 6 Operation mode
0 0 Byte Mode (default)
0 1 Virtual Chip Mode

In Byte Mode one data unit (i.e. 8 bit) can be transferred to or from the SRAM to or from one specified address. In Virtual Chip Mode only the first address is specified, afterwards data will be read or written continuously. An internal address pointer is automatically incremented with each data transfer.

The SRAM supports at least the following commands:

Code (hex) Parameter Return value Description
0x01 New 8-bit pattern for the status register None Set the status register
0x05 NA The current 8-bit value of the status register Read the status register
0x02 16-bit address + at least one 8-bit data value NA Write new data into the memory
0x03 16-bit address At least one 8-bit data value Read data from the memory

Jumper Settings

The following illustration shows jumper settings which provide

  • correct supply voltage
  • correct SPI signal levels
  • the connection of the A3 pin to the _CS pin of the SRAM
for the SRAM.

Uno335 Jumper Setting for SRAM

Example sketch

In this example, we use Euler's number (the E in BlueberryE) e = 2.71828 18284 59045 23536 02874 71352 66249 77572 47093 69995... to illustrate the usage of the SRAM on the Uno335.

Euler's number e is calculated in the setup(). We use the Spigot algorithm of A. H. J. Sale to calculate 4096 digits after the decimal point. These values are stored in the SRAM using the Byte mode.

In each iteration of loop(), 4 digits of e are read from the SRAM are shown in the Serial monitor. To read the values, the SRAM is set to Virtual Chip Mode. After the last digit was read, the sequence starts from the beginning.

In order to use the SPI communication, it is important to understand the special functionality of the SS pin of the ATmega328P. This SS pin has to be set as output and must not be changed (see code lines 35, 36). Otherwise, the ATmega328P will automatically set the itself to SPI slave mode. The SPI library will not work under such condition (see library reference documentation).

And here is the code: download on GitHub


/*
  Calculate Eulers number e and store 4096 digits in the Uno335 Serial Sram.

  created 10 Aug. 2016
  by Engelbert Mittermeier (BlueberryE GmbH)
*/

1:   #include <SPI.h>
2:
3:   // Define the SRAM select pins:
4:   const byte sramSelect = A3;
5:
6:   // Define the operation codes:
7:   const byte sramWriteData = 0x02;
8:   const byte sramReadData = 0x03;
9:   const byte sramWriteStatus = 0x01;
10:
11:  // Define the status modi:
12:  const byte sramByteMode = 0x01;
13:  const byte sramVirtualChipMode = 0x41;
14:
15:  // The SPI settings for the SRAM:
16:  const SPISettings settings4Sram(16000000, MSBFIRST, SPI_MODE0);
17: 
18:  // variables used to control the writing and reading of the digits of e
19:  word sramMaxUsedAddr = 0x0000; 
20:  word sramCurrentAddr = 0x0000;
21:  byte restart = 1;
22:  const byte maxDigitCount = 4;
23:  byte values[maxDigitCount];
24:  byte i;
25:  word avail;
26:
27:  void setup() {
28:     Serial.begin(9600);
29: 
30:     // Set the SRAM select pin
31:     digitalWrite(sramSelect, HIGH);
32:     pinMode(sramSelect, OUTPUT);
33:
34:     // Set the SS pin
35:     digitalWrite(SS, HIGH);
36:     pinMode(SS, OUTPUT);
37:
38:     // Initialize the SPI library
39:     SPI.begin();
40:
41:     // Write e to the SRAM
42:     writeEulerDigits();
43:
44:     // set the SRAM to VIRUTAL CHIP mode
45:    SPI.beginTransaction(settings4Sram);
46:    digitalWrite(sramSelect, LOW);
47:    Serial.println("Set SRAM to Virtual Chip Mode");
48:    SPI.transfer(sramWriteStatus);         // SET STATUS REGISTER command
49:    SPI.transfer(sramVirtualChipMode);     // new 8-bit pattern for the status register
50:    digitalWrite(sramSelect, HIGH);
51:    SPI.endTransaction();
52:  }
53:
54:  void loop() {
55:      if (!restart){
56:          avail = (sramMaxUsedAddr - sramCurrentAddr) + 1;
57:          if (avail > maxDigitCount) avail = maxDigitCount;
58:          else restart = 1;
59:          // Read the next digits
60:          SPI.beginTransaction(settings4Sram);
61:          digitalWrite(sramSelect, LOW);
62:          SPI.transfer(sramReadData);                    // Read DATA command
63:          SPI.transfer((byte) (sramCurrentAddr >> 8));   // MSB of address
64:          SPI.transfer((byte) sramCurrentAddr);          // LSB of address
65:          for (i = 0; i < avail; i++) values[i] = SPI.transfer(0xFF); 
66:          digitalWrite(sramSelect, HIGH);
67:          SPI.endTransaction();
68:          // Print the digits
69:          Serial.print("      ");
70:          for (i = 0; i < avail; i++) Serial.print(values[i], DEC);
71:          Serial.println();
72:          sramCurrentAddr = sramCurrentAddr + 4;
73:      } else {
74:          Serial.println("\nE = 2.");
75:          restart = 0;
76:          sramCurrentAddr = 0x0000;
77:      }
78:      delay(200);
79:  }
80:
81:  // 4096 digits of e are written to the Serial SRAM of the Uno335.
82:  // To do this efficiently with the 8-bit Atmega328P with only 2KB SRAM internal memory, we use the 
83:  // Spigot algorithm of A. Sale.
84:  // see: A. H. J. Sale: The calculation of e to many significant digits. The Computer Journal, Vol. 11 (2), 1968. S. 229–230
85:  void writeEulerDigits(){
86:      int n = 4096;
87:      int m = 1493;
88:      Serial.print("Writing ");Serial.print(n, DEC); Serial.println(" digits of E to the SRAM");
89:      
90:      // set the SRAM to BYTE mode
91:      SPI.beginTransaction(settings4Sram);
92:      digitalWrite(sramSelect, LOW);
93:      Serial.println("Set SRAM to Byte Mode");
94:      SPI.transfer(sramWriteStatus);  // SET STATUS REGISTER command
95:      SPI.transfer(sramByteMode);     // new 8-bit pattern for the status register
96:      digitalWrite(sramSelect, HIGH);
97:      SPI.endTransaction();
98:
99:      byte coef[m + 1];
100:     for (int j = 2; j <= m; j++) coef[j] = 1;
101:
102:     int carry;
103:     int temp;
104:     for (int i = 1; i <= n; i++){
105:         carry = 0;
106:         for (int j = m; j >= 2; j--){
107:             temp = coef[j] * 10 + carry;
108:             carry = temp / j;
109:             coef[j] = temp - carry * j;
110:         }
111:         Serial.print((byte) carry);
112:         SPI.beginTransaction(settings4Sram);
113:         digitalWrite(sramSelect, LOW);
114:         SPI.transfer(sramWriteData);             // WRITE DATA command
115:         SPI.transfer((byte) (sramCurrentAddr >> 8));      // MSB of address0
116:         SPI.transfer((byte) sramCurrentAddr);             // LSB of address0
117:         SPI.transfer((byte) carry);                       //  the value
118:         digitalWrite(sramSelect, HIGH);
119:         SPI.endTransaction();
120:         sramCurrentAddr = sramCurrentAddr + 1;
121:     }
122:     sramMaxUsedAddr = sramCurrentAddr - 1;
123:     Serial.println("\ndone");
124: }

And here is the output of this code:


Writing 4096 digits of E to the SRAM
Set SRAM to Byte Mode
        7182818284590452353602874713526624977572470936999595749669676277240766303535...
done
Set SRAM to Virtual Chip Mode

E = 2.
      7182
      8182
      8459
      0452
      3536
      0287
      4713
      5266
      2497
      7572
      4709
      3699
      9595
      7496
      6967
      6277
      2407
      6630
      3535
      ...