Shop OBEX P1 Docs P2 Docs Learn Events
Has anyone written a driver for Microchip 23LC1024 SRam chip? — Parallax Forums

Has anyone written a driver for Microchip 23LC1024 SRam chip?

I thought I would try to use a 23LC1024 SRam chip to give my programs a bit of Ram.

The initial idea was to split the chip up into 1KB blocks, so 128 in all.
And out of the 128 blocks, I would use 2 blocks (2048 bytes) to create and allocation index.

The remaining 126 blocks would be available to my other programs (which I haven't written yet, its a work in progress)...

And the idea was that a program would request allocation and if its a new request, receive a key/token (to be used in all future requests by the program) and also allocate/reserve the amount of memory requested in 1KB blocks.

So I started off with the Andre' LaMothe sample in the library
SPI SRAM Driver for Microchip 23K356 32K byte SPI SRAM - SRAM_driver_23K256_v010.spin
The one in AN012-Interfacing-the-Propeller-to-External-SRAM-with-SPI application note.

Not long after trying to make it fit my requirements, I realised it was only for SPI, and I really wanted to be able to SDI and SQI modes too. While also trying to support almost the full command set (almost because HOLD is not supported in my driver)

So I decided to write it from scratch, but got bogged down in the logic of program flow or methods, I am having problems in the logic in the checking of blocks already allocated to a program, and also of creating/writing the index record for new allocations.

Problem areas In particular:
1) When the requesting program requests memory allocation block(s),
1.1) Then the Tokens list is checked to see if the program has already been allocated memory
2) If the program has already been allocated memory, then an error is raised
2.1) the program should use ExtendMemory to extend its allocation quota (not started this yet)
2.2) if this is a new request, then I call the allocatememory method
2.3) after some basic checks the allocatememory method calls the registerallocation method
2.4) In the register method, the allocation index record is saved and the allocation metrics stored, thus reserving the memory for that program.

During the sequence above, I guess i'm going about it the wrong way because the single RESULT variable which is returned by a method call is not enough, and I resorted to adding pointers to local variables in the calling method to address this shortfall. And maybe that is the problem, maybe i need to break those checks/calls into smaller methods...

I guess too, that IDEALLY all the variables need to be in the DAT section, so all programs share that data rather than have their own copies, such as the cache, blocktable, tokensindex, etc

But I'm not sure if there is any overheads to storing it in the DAT section, by overheads I mean that i'm not sure if individual bytes or words are accessible, or whether everything is long aligned in the DAT...

If I get it fixed, then I would hope to look at making it standalone (run it its own cog as opposed to in the main cog as subobject.

So I thought, I'd put this question out there, to see if anyone has already written a driver for 23LC1024, so that I can pick it apart and try to correct any errors in my own version.

I'm writing in spin and I don't think any pasm versions would be of help to me.

I've attached my own effort, in case its worth saving, or can be fixed...

Comments

  • Wuerfel_21Wuerfel_21 Posts: 5,106
    edited 2022-01-17 18:05

    There is zero benefit to SQI mode, at all. Do not bother. Reading a single MISO bitstream is just as fast thanks to counter tricks.

    I've attached my ol' 23LC1024 driver. It doesn't really do anything but sequential reads and writes, but really, you don't need anything else, ever.

  • RaymanRayman Posts: 14,755

    Years ago, I believe I had a driver for something called RamPage2

    This had two SQI chips to form a byte bus.

    Driver probably not helpful with single chip though...

  • JaanDohJaanDoh Posts: 129
    edited 2022-01-18 18:27

    @Wuerfel_21 said:
    There is zero benefit to SQI mode, at all. Do not bother. Reading a single MISO bitstream is just as fast thanks to counter tricks.

    I've attached my ol' 23LC1024 driver. It doesn't really do anything but sequential reads and writes, but really, you don't need anything else, ever.

    @Wuerfel_21 , Firstly, thank you for sharing your code, and thank you for explaining that there's really no need for sdi/sqi...

    I don't quite follow the underlying concept of your code, since I don't know pasm, and this is the first time i'm hearing of "counter tricks" and I can see that the read/write methods have been unrolled to make it faster (beyond that I don't understand anything lol.

    Say If I wanted to add a 32 page cache, I assume i can just do so in spin?
    Your code is a fraction of my code and will save me lots of bytes, so thank you lots!

    @Rayman said:
    Years ago, I believe I had a driver for something called RamPage2

    This had two SQI chips to form a byte bus.

    Driver probably not helpful with single chip though...

    @Rayman , Oh I never thought about that, thats quite novel, so you'd get a full byte each time instead of nibble...
    Yeah I guess a single chip driver wont help in that case, but I shouldn't think its too hard to change the code, just case of sychroniising two cogs and having the latter cog put the 2 nibbles together....

    Its whether it improves performance or not that matters I guess, and at what price too? ( at the cost of a second cog?)

    I aim to have 3 of the ram chips all sharing the bus, but I think with the advice and code from @Wuerfel_21 , I'm further down the path then when I started...

  • @JaanDoh said:
    Say If I wanted to add a 32 page cache, I assume i can just do so in spin?

    You could do it either in the PASM driver or in Spin, ye. At the end of the day, you're just reading and writing byte spans.

  • @Wuerfel_21 said:

    @JaanDoh said:
    Say If I wanted to add a 32 page cache, I assume i can just do so in spin?


    You could do it either in the PASM driver or in Spin, ye. At the end of the day, you're just reading and writing byte spans.

    @Wuefel_21
    I wrote the code for the cache and then just REMmed it out because I wasn't sure when to use the cache, though I would hazard a guess to use the cache when reading data sectors and not the index.
    Since I've already scripted the methods, it's simple to unREMark them when needed.

    BUT... I've come against a problem which I don't know how to fix....
    (First some clarification about how the ram is laid out or will be structured)

    The way i intend to use the ram is to split the 1Mbit ram into 128 1-kilobyte blocks/sectors.
    Use the first block as an index that contains 128 index records each 8 bytes long, and the remaining 127 blocks for data.

       'The allocation record is SHARED and volatile - It should not be relied up on
       Byte _baAlcAllocRec[8]                 'This buffer must NOT be relied on as calls by other modules will change this
       '  Byte _bAlcId                        'AllocationId (0 is index/1-127 are available)
       '  Byte _bBlkType                      'Allocation blocktype (C=control/D=data)
       '  Word _wAppId                        'ApplicationId (Id of requestee program accessing/requesting memory)
       '  Byte _bSectorId                     'BlockId/SectorId that this index record describes
       '  Byte _bQtyEntries                   'Number of entries (index/data structures persisted)
       '  Word _wBytesUsed                    'Number of bytes used out of 1024 in the block/sector
    

    On each allocation request, I allocate 1 block of data (1024 bytes) for an object index for the requesting app, and at least 1 block of data for the raw data.

       'The object index record is SHARED and volatile - It should not be relied up on (this is in the control block)
       Byte _baObjIndexRec[10]
       'Byte _bObjId[0]                       'ObjectId
       'Byte _bInstance[1]                    'InstanceId
       'Word _wObjTypeId[2/3]                 'Object type id
       'Word _wObjRecLen[4/5]                 'Object record length
       'Long _lObjDataAddr[6/7/8/9]           'The object record data address (offset from start of data block address)
    

    Looking at the code it should work fine, or maybe even require some minor bug-fixes (bug fixes because part way through programming I just go blank and completely forget whats going on or find it difficult to understand the code, lol.... It's an age thing, since i'm pushing on into senior years).

    Problem
    I've come against a problem, where-by, say if I wan't to remove an allocation (because that cog/program finished and was stopped)... In cases like that I want to REMOVE the allocation, by that I mean clear the index record in block-0/sector-0, and clear the data blocks/sectors to all zero's.

    And the problem is that the code from @Wuerfel_21 does READ'S and WRITE'S, from contiguous data buffers, and what I need is a FILL of the same character (like 0 (zero)) and I don't have the space to spare a 1Kb buffer to use.

  • Wuerfel_21Wuerfel_21 Posts: 5,106
    edited 2022-01-23 16:50

    Adding fills into the driver code should be rather straightforward. Just always reload the same fill value instead of reading from memory.

    Alternatively, if you want to zero-fill, there's a block of 64 zeroes in ROM at $ACC0 (bottom half of ² and ³ characters from the font), so to fill 1k you could just issue 16 write commands from that address.

  • Thank You again.

    I had thought that maybe there was a way of using your pasm code, but think that its written for read/writing from a buffer only.
    And I would think that simply calling the method repeatedly would mean re-sending the address repeatedly too, all this is supposition since I don't know pasm...

    so I just took portions of the old code spin I wrote and patched that in.

    PUB FillRam(pbChar, plRamAddr, pwQtyBytes) : RTNBOOL | tmpStatus, tmpCount
       '
       '-> Init
       RTNBOOL := False
       '
       '-> Check if ready
       tmpStatus := Long[@dbRamStatus_]
       If (tmpStatus == RAM_STATUS_READY)
          '
          '-> Set busy state
          Long[@dbRamStatus_] := RAM_STATUS_BUSY
          '
          '-> Fill Ram
          OutA[_bCsPin] := SYS_LOW            'chip select
          RamSpiTransfer(%0000_0010)          'send WRITE command (%0000_0010)
          'send address
          RamSpiTransfer(((plRamAddr & $FFFFFF) >> 16))
          RamSpiTransfer(((plRamAddr & $FFFF) >> 8))
          RamSpiTransfer(plRamAddr & $FF)
          '
          '-> Write the blanks
          Repeat tmpCount From 0 To pwQtyBytes - 1
             RamSpiTransfer(pbChar)
          'EndRepeat
          OutA[_bCsPin] := SYS_HIGH     'chip deselect
          RTNBOOL := True
          '
          '-> Set ready state
          Long[@dbRamStatus_] := RAM_STATUS_READY
          '
       'EndIf
       '
    'END_PUB
    

    I guess also, that sooner or later I will have to learn pasm lol
    Thank you again.

Sign In or Register to comment.