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-01-07
- Revision:
- 0:69ea2af1d9af
- Child:
- 1:5a261b6a88af
File content as of revision 0:69ea2af1d9af:
/* * 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 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 (SPI& spi, PinName cs, int size) : _spi(spi), _cs(cs) { _spi.frequency(16000000); _cs = 1; _size = size; _alloc = 0; #ifdef RAM_USE_DMA dmacfg0 = new MODDMA_Config; dmacfg1 = new MODDMA_Config; ssp_dmacr = &LPC_SSP1->DMACR; dmacon0 = MODDMA::SSP1_Tx; dmacon1 = MODDMA::SSP1_Rx; dmaexit = 1; #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; #ifdef RAM_USE_DMA dmacfg0 = new MODDMA_Config; dmacfg1 = new MODDMA_Config; if (mosi == p5) { ssp_dmacr = &LPC_SSP1->DMACR; dmacon0 = MODDMA::SSP1_Tx; dmacon1 = MODDMA::SSP1_Rx; } else if (mosi == p11) { ssp_dmacr = &LPC_SSP0->DMACR; dmacon0 = MODDMA::SSP0_Tx; dmacon1 = MODDMA::SSP0_Rx; } dmaexit = 1; #endif #ifdef RAM_USE_FIFO fifo_num = 0; #endif } int SerRAM::write (int addr, int dat) { _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, int async) { int i; #ifdef RAM_USE_DMA static char dummy[RAM_DMA_SIZE]; #endif DBG("DMA write %04x %d\r\n", addr, len); #ifdef RAM_USE_DMA while (! dmaexit); #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 dmaexit = 0; 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 == 0) { while (! dmaexit); 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; _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, int async) { int i; DBG("DMA read %04x %d\r\n", addr, len); #ifdef RAM_USE_DMA while (! dmaexit); #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 dmaexit = 0; 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 == 0) { while (! dmaexit); } #else for (i = 0; i < len; i ++) { buf[i] = _spi.write(0); } _cs = 1; #endif return i; } int SerRAM::setStatus (int status) { _cs = 0; _spi.write(CMD_WRMR); _spi.write(status); _cs = 1; return 0; } int SerRAM::getStatus () { int r; _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 () { dmaexit = 1; _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 () { dmaexit = -1; _cs = 1; DBG("err_callback\r\n"); } #endif #ifdef RAM_USE_FIFO int SerRAM::fifoAlloc (int size) { int n, s; s = ((size + 1) / RAM_DMA_SIZE + 1) * RAM_DMA_SIZE; if (fifo_num >= RAM_FIFO_NUM || (_size * 1024 - _alloc) < s) return -1; n = fifo_num; fifo[n].size = size + 1; fifo[n].buf_w = new char[RAM_DMA_SIZE]; fifo[n].buf_r = new char[RAM_DMA_SIZE]; fifo[n].ram = _alloc; fifoClear(n); fifo_num ++; _alloc += s; DBG("alloc %d + %d (%d)\r\n", fifo[n].ram, fifo[n].size, _alloc); return n; } int SerRAM::fifoPut (int n, char dat) { int next, next2; next = fifo[n].addr_w + 1; next2 = fifo[n].addr2_w + 1; if (next >= fifo[n].size) { // last of fifo next = 0; next2 = 0; } if (next2 >= RAM_DMA_SIZE) { // last of buffer next2 = 0; } if (next == fifo[n].addr_r) { // no data return -1; } #ifdef RAM_USE_DMA while (! dmaexit); // busy DMA #endif fifo[n].buf_w[fifo[n].addr2_w] = dat; if (next2 == 0) { // ring write(fifo[n].ram + fifo[n].ram_w, fifo[n].buf_w, RAM_DMA_SIZE, 1); if (fifo[n].ram_w == fifo[n].ram_r) { // w = r memcpy(fifo[n].buf_r, fifo[n].buf_w, RAM_DMA_SIZE); } fifo[n].ram_w += RAM_DMA_SIZE; if (next == 0) { fifo[n].ram_w = 0; } } fifo[n].addr_w = next; fifo[n].addr2_w = next2; return 0; } int SerRAM::fifoPut (int n, char *buf, int len) { int i; for (i = 0; i < len; i ++) { if (fifoPut(n, buf[i])) return -1; } return 0; } int SerRAM::fifoGet (int n, char *dat) { if (fifo[n].addr_r == fifo[n].addr_w) { // no data return -1; } #ifdef RAM_USE_DMA while (! dmaexit); // busy DMA #endif if (fifo[n].ram_r != fifo[n].ram_w) { *dat = fifo[n].buf_r[fifo[n].addr2_r]; } else if (fifo[n].addr_w < fifo[n].addr_r) { *dat = fifo[n].buf_r[fifo[n].addr2_r]; } else { // w = r and w > r *dat = fifo[n].buf_w[fifo[n].addr2_r]; } fifo[n].addr_r += 1; fifo[n].addr2_r += 1; if (fifo[n].addr_r >= fifo[n].size) { // last of fifo fifo[n].addr_r = 0; fifo[n].addr2_r = 0; } if (fifo[n].addr2_r >= RAM_DMA_SIZE) { // last of buffer fifo[n].addr2_r = 0; } if (fifo[n].addr2_r == 0) { // ring fifo[n].ram_r += RAM_DMA_SIZE; if (fifo[n].addr_r == 0) { fifo[n].ram_r = 0; } read(fifo[n].ram + fifo[n].ram_r, fifo[n].buf_r, RAM_DMA_SIZE); } return 0; } int SerRAM::fifoGet (int n, char *buf, int len) { int i; for (i = 0; i < len; i ++) { if (fifoGet(n, &buf[i])) return -1; } return 0; } int SerRAM::fifoAvailable (int n) { if (fifo[n].addr_w < fifo[n].addr_r) { return fifo[n].addr_r - fifo[n].addr_w - 1; } else { return (fifo[n].size - fifo[n].addr_w) + fifo[n].addr_r - 1; } } int SerRAM::fifoUse (int n) { return fifo[n].size - fifoAvailable(n) - 1; } void SerRAM::fifoClear (int n) { fifo[n].addr_w = 0; fifo[n].addr_r = 0; fifo[n].addr2_w = 0; fifo[n].addr2_r = 0; fifo[n].ram_w = 0; fifo[n].ram_r = 0; read(fifo[n].ram + fifo[n].ram_r, fifo[n].buf_r, RAM_DMA_SIZE); } #endif