Serial RAM (SPI SRAM) library 23K256, 23LC1024 (Microchip) see: http://mbed.org/users/okini3939/notebook/extend-memory/

Dependents:   SPIRAM_23LC1024_FIFO

SerRAM.cpp

Committer:
okini3939
Date:
2013-03-08
Revision:
1:5a261b6a88af
Parent:
0:69ea2af1d9af

File content as of revision 1:5a261b6a88af:

/*
 * Serial RAM (SPI SRAM) library
 * Copyright (c) 2013 Hiroshi Suga
 * Released under the MIT License: http://mbed.org/license/mit
 */

/** @file
 * @brief Serial RAM (SPI SRAM) library
 *   23K256, 23LC1024 (Microchip)
 *   support FIFO
 *   support DMA need http://mbed.org/users/AjK/code/MODDMA/
 */
 
#include "mbed.h"
#include "SerRAM.h"

#define DBG(...)
//#define DBG(...) printf("" __VA_ARGS__) 

#define CMD_READ    0x03
#define CMD_WRITE   0x02
#define CMD_RDMR    0x05
#define CMD_WRMR    0x01

#define MODE_BYTE   0x00
#define MODE_SEQ    0x40

SerRAM * SerRAM::_inst;

SerRAM::SerRAM (SPI& spi, PinName cs, int size) : _spi(spi), _cs(cs) {
    _spi.frequency(16000000);
    _cs = 1;
    _size = size;
    _alloc = 0;
    _inst = this;

#ifdef RAM_USE_DMA
    dmacfg0 = new MODDMA_Config;
    dmacfg1 = new MODDMA_Config;
    _ssp = LPC_SSP1; // ???
    dmacon0 = MODDMA::SSP1_Tx;
    dmacon1 = MODDMA::SSP1_Rx;
    dmabusy = false;
#endif

#ifdef RAM_USE_FIFO
    fifo_num = 0;
#endif
}

SerRAM::SerRAM (PinName mosi, PinName miso, PinName sck, PinName cs, int size) : _spi(mosi, miso, sck), _cs(cs) {
    _spi.frequency(16000000);
    _cs = 1;
    _size = size;
    _alloc = 0;
    _inst = this;

#ifdef RAM_USE_DMA
    dmacfg0 = new MODDMA_Config;
    dmacfg1 = new MODDMA_Config;
    if (mosi == p5) {
        _ssp = LPC_SSP1;
        dmacon0 = MODDMA::SSP1_Tx;
        dmacon1 = MODDMA::SSP1_Rx;
    } else
    if (mosi == p11) {
        _ssp = LPC_SSP0;
        dmacon0 = MODDMA::SSP0_Tx;
        dmacon1 = MODDMA::SSP0_Rx;
    }
    dmabusy = false;
#endif

#ifdef RAM_USE_FIFO
    fifo_num = 0;
#endif
}

int SerRAM::write (int addr, int dat) {

#ifdef RAM_USE_DMA
    while (dmabusy);
#endif
    _cs = 0;
    _spi.write(CMD_WRITE);
    if (_size > 512) {
        _spi.write((addr >> 16) & 0xff);
    }
    _spi.write((addr >> 8) & 0xff);
    _spi.write(addr & 0xff);
    _spi.write(dat);
    _cs = 1;
    return 0;
}

int SerRAM::write (int addr, char *buf, int len, bool async) {
    int i;
#ifdef RAM_USE_DMA
    static char dummy[RAM_DMA_SIZE];
#endif

    DBG("write %04x %d\r\n", addr, len);
#ifdef RAM_USE_DMA
    while (dmabusy);
#endif
    _cs = 0;
    _spi.write(CMD_WRITE);
    if (_size > 512) {
        _spi.write((addr >> 16) & 0xff);
    }
    _spi.write((addr >> 8) & 0xff);
    _spi.write(addr & 0xff);
    
#ifdef RAM_USE_DMA
    if (len > RAM_DMA_SIZE) len = RAM_DMA_SIZE;

    dmacfg0
     ->channelNum    ( MODDMA::Channel_0 )
     ->srcMemAddr    ( (uint32_t)buf )
     ->dstMemAddr    ( dmacon0 )
     ->transferSize  ( len )
     ->transferType  ( MODDMA::m2p )
     ->dstConn       ( dmacon0 )
     ->attach_tc     ( this, &SerRAM::tc0_callback )
     ->attach_err    ( this, &SerRAM::err_callback )
    ; // config end
 
    dmacfg1
     ->channelNum    ( MODDMA::Channel_1 )
     ->srcMemAddr    ( dmacon1 )
     ->dstMemAddr    ( (uint32_t)dummy )
     ->transferSize  ( len )
     ->transferType  ( MODDMA::p2m )
     ->srcConn       ( dmacon1 )
     ->attach_tc     ( this, &SerRAM::tc1_callback )
     ->attach_err    ( this, &SerRAM::err_callback )
    ; // config end
    
    dmabusy = true;
    if (dma.Setup( dmacfg0 ) && dma.Setup( dmacfg1 )) {
        DBG("DMA setup\r\n");
        _ssp->DMACR = (1<<1)|(1<<0); // TX,RXDMAE
        dma.Enable( dmacfg0 );
        dma.Enable( dmacfg1 );
        DBG("DMA enable\r\n");
        i = 0;
    } else {
        DBG("DMA error\r\n");
        i = -1;
    }

    if (async == false) {
        while (dmabusy);
        DBG("DMA done\r\n");
    }
#else
    for (i = 0; i < len; i ++) {
        _spi.write(buf[i]);
    }
    _cs = 1;
#endif
    return i;
}

int SerRAM::read (int addr) {
    int dat;

#ifdef RAM_USE_DMA
    while (dmabusy);
#endif
    _cs = 0;
    _spi.write(CMD_READ);
    if (_size > 512) {
        _spi.write((addr >> 16) & 0xff);
    }
    _spi.write((addr >> 8) & 0xff);
    _spi.write(addr & 0xff);
    dat = _spi.write(0);
    _cs = 1;
    return dat;
}

int SerRAM::read (int addr, char *buf, int len, bool async) {
    int i;

    DBG("read %04x %d\r\n", addr, len);
#ifdef RAM_USE_DMA
    while (dmabusy);
#endif
    _cs = 0;
    _spi.write(CMD_READ);
    if (_size > 512) {
        _spi.write((addr >> 16) & 0xff);
    }
    _spi.write((addr >> 8) & 0xff);
    _spi.write(addr & 0xff);

#ifdef RAM_USE_DMA
    dmacfg0
     ->channelNum    ( MODDMA::Channel_0 )
     ->srcMemAddr    ( (uint32_t)buf )
     ->dstMemAddr    ( dmacon0 )
     ->transferSize  ( len )
     ->transferType  ( MODDMA::m2p )
     ->dstConn       ( dmacon0 )
     ->attach_tc     ( this, &SerRAM::tc0_callback )
     ->attach_err    ( this, &SerRAM::err_callback )
    ; // config end

    dmacfg1
     ->channelNum    ( MODDMA::Channel_1 )
     ->srcMemAddr    ( dmacon1 )
     ->dstMemAddr    ( (uint32_t)buf )
     ->transferSize  ( len )
     ->transferType  ( MODDMA::p2m )
     ->srcConn       ( dmacon1 )
     ->attach_tc     ( this, &SerRAM::tc1_callback )
     ->attach_err    ( this, &SerRAM::err_callback )
    ; // config end
    
    dmabusy = true;
    if (dma.Setup( dmacfg0 ) && dma.Setup( dmacfg1 )) {
        _ssp->DMACR = (1<<1)|(1<<0); // TX,RXDMAE
        dma.Enable( dmacfg0 );
        dma.Enable( dmacfg1 );
        i = 0;
    } else {
        DBG("DMA error\r\n");
        i = -1;
    }

    if (async == false) {
        while (dmabusy);
    }
#else
    for (i = 0; i < len; i ++) {
        buf[i] = _spi.write(0);
    }
    _cs = 1;
#endif
    return i;
}

int SerRAM::setStatus (int status) {

#ifdef RAM_USE_DMA
    while (dmabusy);
#endif
    _cs = 0;
    _spi.write(CMD_WRMR);
    _spi.write(status);
    _cs = 1;
    return 0;
}

int SerRAM::getStatus () {
    int r;

#ifdef RAM_USE_DMA
    while (dmabusy);
#endif
    _cs = 0;
    _spi.write(CMD_RDMR);
    r = _spi.write(0);
    _cs = 1;
    return r;
}

#ifdef RAM_USE_DMA
void SerRAM::tc0_callback () {

    MODDMA_Config *config = dma.getConfig();
    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );

    // Clear DMA IRQ flags.
    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();    
    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();    
    DBG("tc0_callback\r\n");
}

void SerRAM::tc1_callback () {

    dmabusy = false;
    _cs = 1;
    _ssp->DMACR = 0;
    
    MODDMA_Config *config = dma.getConfig();
    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );

    // Clear DMA IRQ flags.
    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();
    DBG("tc1_callback\r\n");
}

void SerRAM::err_callback () {
    dmabusy = false;
    _cs = 1;
    DBG("err_callback\r\n");
}
#endif