Electronic – arduino – How to use the flash memory on the Copperhead WiFi Shield

arduinoflash

I recently purchased a Copperhead WiFi Shield for Arduino, and I have successfully initiated some basic networking over the wifi.

I've noticed that on my Revision of the board (rev.2) there is also a 16Mbit serial flash, "for storing web pages and other data!" is the way they put it. Does anybody have experiencing using this board? I find the documentation is extremely lacking, and really all they give is a lot of source code with what I find to be poor examples to build on. Any advice on how I can take advantage of the flash memory would be really appreciated.

In some of the sources they have code similar to the following. Is this essentially writing the data to the flash memory?

const prog_char webpage[] PROGMEM = {"<html>...webpage truncated for brevity...</html>"};

Best Answer

I'm not entirely sure of this, without a datasheet or manual for the shield there's no way to be sure. (other than trying it out)

It seems to use SPI flash, which means that it uses the SPI protocol to transfer data.

Firstly, join the MISO/MOSI/SCK pins on the two devices. Also connect Arduino pin 10 to the ChipSelect of the device. (It is quite possible that these pins are already connected -- at least the LinkSprite site seems to say so)

Transferring data to be stored/read from external memory via SPI is explained rather well here. I'll copy the final code over:

Note that the code is for an EEPROM chip, but it ought to work here as well.

#define DATAOUT 11//MOSI
#define DATAIN  12//MISO 
#define SPICLOCK  13//sck
#define SLAVESELECT 10//ss

//opcodes
#define WREN  6
#define WRDI  4
#define RDSR  5
#define WRSR  1
#define READ  3
#define WRITE 2

byte eeprom_output_data;
byte eeprom_input_data=0;
byte clr;
int address=0;
//data buffer
char buffer [128];

void fill_buffer()
{
  for (int I=0;I<128;I++)
  {
    buffer[I]=I;
  }
}

char spi_transfer(volatile char data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}

void setup()
{
  Serial.begin(9600);

  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //disable device
  // SPCR = 01010000
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/4 rate (fastest)
  SPCR = (1<<SPE)|(1<<MSTR);
  clr=SPSR;
  clr=SPDR;
  delay(10);
  //fill buffer with data
  fill_buffer();
  //fill eeprom w/ buffer
  digitalWrite(SLAVESELECT,LOW);
  spi_transfer(WREN); //write enable
  digitalWrite(SLAVESELECT,HIGH);
  delay(10);
  digitalWrite(SLAVESELECT,LOW);
  spi_transfer(WRITE); //write instruction
  address=0;
  spi_transfer((char)(address>>8));   //send MSByte address first
  spi_transfer((char)(address));      //send LSByte address
  //write 128 bytes
  for (int I=0;I<128;I++)
  {
    spi_transfer(buffer[I]); //write data byte
  }
  digitalWrite(SLAVESELECT,HIGH); //release chip
  //wait for eeprom to finish writing
  delay(3000);
  Serial.print('h',BYTE);
  Serial.print('i',BYTE);
  Serial.print('\n',BYTE);//debug
  delay(1000);
}

byte read_eeprom(int EEPROM_address)
{
  //READ EEPROM
  int data;
  digitalWrite(SLAVESELECT,LOW);
  spi_transfer(READ); //transmit read opcode
  spi_transfer((char)(EEPROM_address>>8));   //send MSByte address first
  spi_transfer((char)(EEPROM_address));      //send LSByte address
  data = spi_transfer(0xFF); //get data byte
  digitalWrite(SLAVESELECT,HIGH); //release chip, signal end transfer
  return data;
}

void loop()
{
  eeprom_output_data = read_eeprom(address);
  Serial.print(eeprom_output_data,DEC);
  Serial.print('\n',BYTE);
  address++;
  if (address == 128)
    address = 0;
  delay(500); //pause for readability
}

This code ought to work for the Copperhead shield as well. If not, there's this code for SPI flash (from here):

#include <SPI.h>
#include <Peggy2.h>

#define SS_PIN  16

Peggy2 frame1;
byte toDisp = 0;
byte checker = 0;

void setup()
{
    frame1.HardwareInit();
    pinMode(SS_PIN,OUTPUT); //set pin16 to output, SS pin
    SPI.setClockDivider(SPI_CLOCK_DIV2); //set the SPI clock to f/2, fastest possible
    SPI.begin();    //SPI lib function which sets ddr for SCK and MOSI pin
                    //MISO is auto input
                    //see SPI.cpp for more info

}

void loop()
{

    if(!checker){
                enableProgramming();
        programData();
        toDisp = receiveByte(0);
        checker = 1;
        frame1.WriteRow(0,toDisp);
    }
    frame1.RefreshAll(2);

}

byte receiveByte(unsigned long startAddress)
{
    //Begin High Speed Read Instruction
    //See p. 10 of SST data sheet
    digitalWrite(SS_PIN,LOW);
    SPI.transfer(0x0B); //high speed read instruction
    SPI.transfer(0x00); //next 3 transfers are address bits A32 - A0
    SPI.transfer(0x00); //So this will read the first byte on the chip
    SPI.transfer(0x00); //last address bits
    SPI.transfer(0xFF); //dummy byte is required to start sending data back to uP
    SPI.transfer(0xFF); //I'm hoping that if I transfer a bullshit byte, the flash
                        //chip will transfer it's data to me in the same time
    digitalWrite(SS_PIN,HIGH);
    //End High Speed Read Instruction   
    return SPDR;    
}

//will perform the read instruction starting from
//startAddress and will receive numOfBytes bytes in
//succession
void receiveBytes(int numOfBytes, unsigned long startAddress)
{
    digitalWrite(SS_PIN,LOW);
    SPI.transfer(0x0B);//high speed read instruction

}

//will perform:
// 1) Chip Erase
// and loop through:
// 1) Page Program
// 2) increment Page
//until the data has finished **note this can loop and over write beginning of memory
void programData(){
    //Begin ChipErase Instruction
    //See p. 17 of SST data sheet
    digitalWrite(SS_PIN,LOW);
    SPI.transfer(0x60);//chip erase instruction
    digitalWrite(SS_PIN,HIGH);
    delay(50);//spec'd time for CE to finish
                //don't bother polling because time to program is irrelevant
    //End ChipErase Instruction

        //Begin WREN Instruction
    //See p. 18 of SST data sheet
    digitalWrite(SS_PIN,LOW);
    SPI.transfer(0x06);//write enable instruction
    digitalWrite(SS_PIN,HIGH);
    //End WREN Instruction

    digitalWrite(SS_PIN,LOW);
    SPI.transfer(0x02); //page program instruction
    SPI.transfer(0x00); //first 8 address bits
    SPI.transfer(0x00); //2nd 8 address bits
    SPI.transfer(0x00); //3rd 8 address bits
    SPI.transfer(0xAA); //10101010 is the byte I should be writing
    digitalWrite(SS_PIN,HIGH);
    delayMicroseconds(3000); //wait 3 ms for page program


    /*
    //Begin Page-Program Instruction
    //see p. 13 of SST data sheet
    byte firstAddress = 0;
    byte secondAddress = 0;
    //this loop will write to every byte in the chips memory
    //32,768 pages of 256 bytes = 8,388,608 bytes
    for(unsigned int i = 0; i < 32,768; ++i) //long variable is number of pages
    {
        digitalWrite(SS_PIN,LOW);
        ++secondAddress; //cycles from 0 to 255, counts pages
        firstAddress = i>>8; // floor(i/256)

        SPI.transfer(0x02);//Page-Program instruction byte
        SPI.transfer(firstAddress); //increments every 256 pages i.e. at page 256 this should be 1
        SPI.transfer(secondAddress); //increments every 256 bytes, i.e every page
        SPI.transfer(0x00); //beginning of a page boundary
        for(int j = 0; j < 256; ++j) //number of bytes per page
        {
            SPI.transfer(2program[(256*i) + j]);//data byte transfer            
        }
        digitalWrite(SS_PIN,HIGH);
        delayMicroseconds(2500); //2500us (2.5ms) delay for each page-program instruction to execute
    }
    //End Page-Program Instruction
    */
}

//Will prepare the chip for writing by performing:
// 1) arm the status register
// 2) Write Enable instruction
//Only needs to be performed once!
void enableProgramming(){
    //Begin EWSR & WRSR Instructions
    //See p. 20 of SST data sheet for more info
    digitalWrite(SS_PIN,LOW); //lower the SS pin
    SPI.transfer(0x50); //enable write status register instruction
    digitalWrite(SS_PIN,HIGH); //raise the SS pin
    delay(10);
    digitalWrite(SS_PIN,LOW); //lower the SS pin
    SPI.transfer(0x01); //write the status register instruction
    SPI.transfer(0x00);//value to write to register
                //xx0000xx will remove all block protection
    digitalWrite(SS_PIN,HIGH);
    //End EWSR & WRSR Instructions

    //Begin WREN Instruction
    //See p. 18 of SST data sheet
    digitalWrite(SS_PIN,LOW);
    SPI.transfer(0x06);//write enable instruction
    digitalWrite(SS_PIN,HIGH);
    //End WREN Instruction

}