Writing to flash memory for AT45DB161D?

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I was pointed to this forum by an Atmel tech representative to post a question about writing to flash memory for the AT45DB161D (which has 2MB flash memory). My project is pretty simple in that it samples data from an analog to digital converter for an extended period of time and stores the results in an array. When the array fills up, I need to move it to flash memory.

My problem is that I have been unable to figure out how to read/write to flash memory. I cannot find any examples in C that show how this can be done. I feel like I’m spinning my wheels on something that should be pretty straightforward.

Can anyone point me in a direction of a code sample of how this can be done? I am using the SPDAT register to transfer the data, but no luck.

This is my first post so if I need to provide more information, please let me know.

Thanks in advance,
-Mike Z.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I am using the SPDAT register to transfer the data
As the flash is a SPI based device you need to initialise the SPI before any comms can happen.

So I would suggest:

A diagram of how the chip is REALLY wired.

Which AVR are you using and any relevant info about the board.

Post the code as you think it should be. There should be a few examples around, I know there is one in ASM.

Read the data sheets, Read the data sheets, Read the data sheets, Read the data sheets... keyboard got stuck :?

oh and which flavour of C compiler you are using.

2nd edit get the AVR335 application note, it may have all you want. Why didn't the FAE tell you that? :roll:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I posted some AT45DB161D routines here previously (a file called dflash.c). Wonder if a search will find it...

...yup, found it:

https://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are not inferring that..no, not possible..didn't actually search?? :shock:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All,

Thanks so much for the quick replies (this board rocks!). I'll check into this information this weekend and report back.

Thanks again!
-Mike Z.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello again,

I took the code from the link above (dflash.c) and tried to get this to work, but I am stuck in 2 procedures, which might be the crux of my problems:

void dflash_chip_select(void)
{
    PORTB &= ~(1 << DF_CHIP_SELECT);               // enable DataFlash by taking _CS low
}

void dflash_chip_unselect(void)
{
    PORTB |= (1 << DF_CHIP_SELECT);               // disable DataFlash by taking _CS low which may start any pending operation
}

I have a couple questions:

- I cannot find in the datasheet for the AT45DB161D what "PORTB" should be defined as.

- DF_CHIP_SELECT resolves to PB4, which also doesn't appear in the datasheet.

I've tried a few things but my guess is if these are not properly defined, I cannot successfully read/write to flash memory.

I'm compiling this with Keil (not sure that helps or not). Also, my sample app calls the dflash.c procedures as follows:

  // write data to flash...
  dflash_chip_select();
  dflash_start_write_active();
  // write a few bytes...
  dflash_write_byte(1);
  dflash_write_byte(2);
  dflash_write_byte(3);
  dflash_flush_buffer(); // not sure I need this?
  dflash_chip_unselect();

  // Now read flash, I have the output dumped to an array that I added to the procedure below.
  dump_flash();

When I print out what's in the array, it's consistently "FF". Any ideas?

Thanks,
-Mike Z.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think Keil makes a compiler for AVR, so I would guess you are actually using one of the Atmel 8051 based micros. In this case, the I/O ports of the micro are P0, P1, ..., instead of PORTA, PORTB, ... The ports are also configured in different ways.

I didn't look at the linked sample, but I would assume it was for AVR in which case there will probably be other issues as well.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, that makes more sense to me. This is set up on P2.3, so I'm assuming I could do something like:

void dflash_chip_select(void)
{
    P2.3=0   // enable DataFlash by taking _CS low
}

void dflash_chip_unselect(void)
{
    P2.3=1     // disable DataFlash by taking _CS low which may start any pending operation
} 

Even with that, it still doesn't appear to work. When I write to SPI, it appears to "work" in that the code executes, yet the memory is always FF when I read it back.

I guess there could be a wiring issue, but this is unlikely. I'm using the Atmel AT89STK-05 starter kit
based on the AT89C5131.

-Mike Z.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

here is my C driver for Atmel dataflash. It works fine in ATmega88/168:

#include 
#include "dataflash.h"


void write_SPI(unsigned char data)
{
       SPDR = data;
       while (!(SPSR & 0x80));             // wait for data transfer to be completed
}
/*-------------------------------------------------------------------------------------------------*/
void init_dataflash (void)
{
  DDRD |= DF_WRITE_PROTECT;
  DF_WRITE_PROTECT_PORT |= DF_WRITE_PROTECT; //Write protect disabled
  DDRD |= DF_RESET; //reset
  DF_RESET_PORT |= DF_RESET; //dis rst
  DDRD &= ~DF_RDY_BUSY;
  PORTD |= DF_RDY_BUSY;
}
/*-------------------------------------------------------------------------------------------------*/
void erase_dataflash(void)
{
   global_mem_ptr -> block_count = 0; //set block count 0
   global_mem_ptr -> page_count = 0;
    SPCR = 0x5C; // interrupt disabled, SPI port enabled, master mode, MSB first,  SPI mode 3, Fcl/4
    while (global_mem_ptr -> block_count <= BLOCK_COUNT)
    {

        DF_CHIP_SELECT_PORT &= ~DF_CHIP_SELECT;           // enable DataFlash
        write_SPI(BLOCK_ERASE);
        write_SPI((unsigned char)( global_mem_ptr -> block_count>>4));
        write_SPI((unsigned char)( global_mem_ptr -> block_count<<4));
        write_SPI(0x00);
        DF_CHIP_SELECT_PORT |= DF_CHIP_SELECT;            // disable DataFlash

        global_mem_ptr -> block_count++;
         while(!(DF_RDY_BUSY_PORT & DF_RDY_BUSY));              // wait until block is erased

    }

    SPCR = 0x00;                            //disable SPI
}
/*-------------------------------------------------------------------------------------------------*/
unsigned char write_to_flash(unsigned char data)
{
    SPCR = 0x5C; // interrupt disabled, SPI port enabled, master mode, MSB first,  SPI mode 3, Fcl/4
    while(!(DF_RDY_BUSY_PORT & DF_RDY_BUSY));      // check if flash is busy

//    DF_CHIP_SELECT_PORT &= ~DF_CHIP_SELECT;        // enable DataFlash

       // free space in buffer 1

        write_SPI(BUFFER_2_WRITE);                //write buffer 1
        write_SPI(0x00);                         // don't cares
        write_SPI((char)( global_mem_ptr -> buffer1_count>>8));    // don't cares plus first two bits of buffer address
        write_SPI((char)(global_mem_ptr -> buffer1_count));         // buffer address (max. 2^8 = 256 pages)
        write_SPI(data);                   // write data into SPI Data Register
        // while (!(SPSR & 0x80));

        global_mem_ptr -> buffer1_count++;          //add 1 to buffer_counter
        DF_CHIP_SELECT_PORT |= DF_CHIP_SELECT;      // disable DataFlash

    if ( global_mem_ptr -> buffer1_count  >= BUFFER_SIZE )     //if buffer is full
          {
           global_mem_ptr -> buffer1_count = 0x00;
            if (global_mem_ptr -> page_count < (PAGE_COUNT ))
               {
//                DF_CHIP_SELECT_PORT &= ~DF_CHIP_SELECT;     // enable DataFlash
                while(!(DF_RDY_BUSY_PORT & DF_RDY_BUSY));      // check if flash is busy
                write_SPI(B2_TO_MM_PAGE_PROG_WITHOUT_ERASE);                    // write data from buffer1 to page
                write_SPI((unsigned char)( global_mem_ptr -> page_count>>6));         // 3 don'cares and 5 page addr
                write_SPI((unsigned char)( global_mem_ptr -> page_count<<1));         // 9 addr. bit
                write_SPI(0x00);                                             // don't cares
               // while (!(SPSR & 0x80));
                global_mem_ptr -> page_count++;
                DF_CHIP_SELECT_PORT |= DF_CHIP_SELECT;                       // disable DataFlash
                // while( !(UCSR0A & (1<<UDRE0)) );      // wait for USART tx pass interrupt
                 return MEMORY_NOT_FULL;

               }
          DF_CHIP_SELECT_PORT |= DF_CHIP_SELECT;                       // disable DataFlash
          return MEMORY_FULL;

          }
}
/*-------------------------------------------------------------------------------------------------*/
void shift_page_to_buffer (unsigned int page, unsigned char buffer)
{
   SPCR = 0x5C; // interrupt disabled, SPI port enabled, master mode, MSB first,  SPI mode 3, Fcl/4
    while(!(DF_RDY_BUSY_PORT & DF_RDY_BUSY));              // wait until flash is not busy

    DF_CHIP_SELECT_PORT &= ~DF_CHIP_SELECT;               // enable DataFlash

    if (buffer == 1)                 // if buffer1 is the active buffer
    {
          write_SPI(MM_PAGE_TO_B1_XFER);    // transfer next page to buffer1
    }
    else                                    // else
    {
           write_SPI(MM_PAGE_TO_B2_XFER);   // transfer next page to buffer2
    }
    write_SPI((unsigned char)(page >> 6));
    write_SPI((unsigned char)(page << 1));
    write_SPI(0x00);
    //while (!(SPSR & 0x80));
    DF_CHIP_SELECT_PORT |= DF_CHIP_SELECT;  // disable DataFlash and start transaction
   // SPCR = 0x00;
}
/*-------------------------------------------------------------------------------------------------*/
 void buffer_to_USART (unsigned char buffer)
{
    unsigned int buffer_counter = (BUFFER_SIZE);
    SPCR = 0x5C; // interrupt disabled, SPI port enabled, master mode, MSB first,  SPI mode 3, Fcl/4

    while(!(DF_RDY_BUSY_PORT & DF_RDY_BUSY));
    DF_CHIP_SELECT_PORT &= ~DF_CHIP_SELECT;               // enable DataFlash

    if (buffer == 1)                 // if buffer1 is the active buffer
    {
        write_SPI(BUFFER_1_READ);           // read from buffer1
    }
    else                                    // else
    {
        write_SPI(BUFFER_2_READ);               // read from buffer2
    }
    write_SPI(0x00);                          // write don't care byte
    write_SPI(0x00);                          // write don't care byte + buffer address 0
    write_SPI(0x00);                          // start at buffer address 0
    write_SPI(0x00);                          // write don't care byte

    do                                        //do - while loop
      {
        write_SPI(0xFF);                      // write dummy value to start register shift
        while( !(UCSR0A & (1<<UDRE0)) );      // wait for USART tx pass interrupt
        UDR0 = SPDR;                          // send data from spi data register to usart tx register
        UCSR0A &= (~UDRE0);                   // clear the signal flag
       } while (--buffer_counter);            // is Buffer transfer complete: 0 = yes

      // while (!(SPSR & 0x80));
     DF_CHIP_SELECT_PORT |= DF_CHIP_SELECT;  // disable DataFlash
     // SPCR = 0x00;
}

.. and header file:

#ifndef DATAFLASH_H_

#define DATAFLASH_H_

#include 

//Global status register flags
#define CLEARED 0x02

// Function returns
#define MEMORY_FULL 0
#define MEMORY_NOT_FULL 1

//Memory architecture
#define PAGE_COUNT 4096
#define BLOCK_COUNT 512
#define SECTOR_COUNT 10
#define BUFFER_SIZE 264

//Ports and pins defines
#define DF_RESET_PORT PORTD
#define DF_RDY_BUSY_PORT PIND
#define DF_WRITE_PROTECT_PORT PORTD
#define DF_CHIP_SELECT_PORT PORTB

#define DF_RESET 0x40                         // DataFlash reset port pin (PD 6)
#define DF_RDY_BUSY 0x20                      // DataFlash ready/busy status port pin (PD 5)
#define DF_WRITE_PROTECT 0x80                 // DataFlash boot sector write protection (PD 7)
#define DF_CHIP_SELECT 0x02                   // DataFlash chip select port pin (PB 1)

#define BUFFER_1 0x00                         // buffer 1
#define BUFFER_2 0x01                         // buffer 2

// defines for all opcodes
#define BUFFER_1_WRITE 0x84                  // buffer 1 write
#define BUFFER_2_WRITE 0x87                  // buffer 2 write
#define BUFFER_1_READ 0x54                   // buffer 1 read
#define BUFFER_2_READ 0x56                   // buffer 2 read
#define B1_TO_MM_PAGE_PROG_WITH_ERASE 0x83   // buffer 1 to main mem page program with built-in erase
#define B2_TO_MM_PAGE_PROG_WITH_ERASE 0x86   // buffer 2 to main mem page program with built-in erase
#define B1_TO_MM_PAGE_PROG_WITHOUT_ERASE 0x88// buffer 1 to main mem page pgm without built-in erase
#define B2_TO_MM_PAGE_PROG_WITHOUT_ERASE 0x89// buffer 2 to main mem page pgm without built-in erase
#define MM_PAGE_PROG_THROUGH_B1 0x82         // main memory page program through buffer 1
#define MM_PAGE_PROG_THROUGH_B2 0x85         // main memory page program through buffer 2
#define AUTO_PAGE_REWRITE_THROUGH_B1 0x58    // auto page rewrite through buffer 1
#define AUTO_PAGE_REWRITE_THROUGH_B2 0x59    // auto page rewrite through buffer 2
#define MM_PAGE_TO_B1_COMP 0x60              // main memory page compare to buffer 1
#define MM_PAGE_TO_B2_COMP 0x61              // main memory page compare to buffer 2
#define MM_PAGE_TO_B1_XFER 0x53              // main memory page to buffer 1 transfer
#define MM_PAGE_TO_B2_XFER 0x55              // main memory page to buffer 2 transfer

// DataFlash status register for reading density, compare status,
#define STATUS_REGISTER 0x57             // and ready/busy status
#define MAIN_MEMORY_PAGE_READ 0x52       // main memory page read
#define PAGE_ERASE 0x81                  // erase a 528 byte page
#define BLOCK_ERASE 0x50                 // erase 512 pages

typedef struct {
unsigned short  page_count;      //max 4095
unsigned short  block_count;     //max 511
unsigned short  buffer1_count;    //max 264
unsigned short  buffer2_count;    //max 264
unsigned char   sector_count;    //max 9
}mem_struct;
mem_struct *global_mem_ptr;

//void write_SPI(unsigned char data);
void init_dataflash (void);
void erase_dataflash(void);
unsigned char write_to_flash(unsigned char data);  //if flash is full 0 else 1
void shift_page_to_buffer (unsigned int page, unsigned char buffer);
void buffer_to_USART (unsigned char buffer);

#endif

Hope that helps you!