A module to store data on a fram.

Dependents:   oldheating motorhome heating

Files at this revision

API Documentation at this revision

Comitter:
andrewboyson
Date:
Fri Apr 23 08:20:00 2021 +0000
Commit message:
Stores data on the FRAM

Changed in this revision

fram.c Show annotated file Show diff for this revision Revisions of this file
fram.h Show annotated file Show diff for this revision Revisions of this file
spi.c Show annotated file Show diff for this revision Revisions of this file
spi.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r e8f4aff306cd fram.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fram.c	Fri Apr 23 08:20:00 2021 +0000
@@ -0,0 +1,143 @@
+#include <string.h>
+#include <stdbool.h>
+
+#include "spi.h"
+#include "log.h"
+#include "fram.h"
+
+#define WREN  0x06 // Set Write Enable Latch   0000 0110B
+#define WRDI  0x04 // Reset Write Enable Latch 0000 0100B
+#define RDSR  0x05 // Read Status Register     0000 0101B
+#define WRSR  0x01 // Write Status Register    0000 0001B
+#define READ  0x03 // Read Memory Code         0000 0011B
+#define WRITE 0x02 // Write Memory Code        0000 0010B
+#define RDID  0x9F // Read Device ID           1001 1111B
+
+#define FRAM_ID     0x047f0302
+#define FRAM_MAGIC  42          //Magic number to show that the FRAM has been intialised
+
+bool FramEmpty; //Set in FramInit
+int  FramUsed;  //Initialised in FramInit and used by FramAllocate to remember the next available location
+
+int FramAllocate(int size) //Allocates a number of bytes in FRAM 
+{
+    int start = FramUsed;
+    int used = FramUsed + size;
+    if (used > FRAM_SIZE - 1)
+    {
+        Log("FramAllocate - No more room in FRAM\r\n");
+        return -1;
+    }
+    FramUsed = used;
+    return start;
+}
+int FramInit()
+{
+    //Configure SPI
+    SpiInit();
+    
+    //Check if the FRAM is connected and working properly
+    SpiChipSelect(0);
+    SpiTransfer(RDID);
+    int id = 0;
+    id = (id << 8) + SpiTransfer(0);
+    id = (id << 8) + SpiTransfer(0);
+    id = (id << 8) + SpiTransfer(0);
+    id = (id << 8) + SpiTransfer(0);
+    SpiChipSelect(1);
+    if (id != FRAM_ID)
+    {
+        LogF("FramInit - Expected FRAM id %08x but got %08x\r\n", FRAM_ID, id);
+        return -1;
+    }
+    
+    //Check the first byte to see if the FRAM is initialised and zero if not
+    SpiChipSelect(0);
+    SpiTransfer(READ);
+    SpiTransfer(0);
+    SpiTransfer(0);
+    char magic = SpiTransfer(0);
+    SpiChipSelect(1);
+    FramEmpty = magic != FRAM_MAGIC;
+    if (FramEmpty)
+    {
+        LogF("FramInit - Byte 0 value %d is not the magic value %d so initialising FRAM to zero\r\n", magic, FRAM_MAGIC);
+        SpiChipSelect(0);
+        SpiTransfer(WREN);
+        SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1);
+        SpiChipSelect(0);
+        SpiTransfer(WRITE);
+        SpiTransfer(0);
+        SpiTransfer(0);
+        SpiTransfer(FRAM_MAGIC);                           //Set the magic number in byte 0
+        for(int i = 1; i < FRAM_SIZE; i++) SpiTransfer(0); //Zero all other locations
+        SpiChipSelect(1);
+    }
+    FramUsed = 1; //Set the next available location to one past the byte used for the magic number
+    return 0;
+}
+void FramWrite(int address, int len, void* pVoid)
+{
+    if (address + len > FRAM_SIZE - 1 || address < 0)
+    {
+        Log("FramWrite - Invalid FRAM address\r\n");
+        return;
+    }
+    SpiChipSelect(0);
+    SpiTransfer(WREN);
+    SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); //Deselect must be at least 60ns. One operation at 96MHz is about 10ns
+    SpiChipSelect(0);
+    SpiTransfer(WRITE);
+    SpiTransfer(address >> 8);
+    SpiTransfer(address & 0xFF);
+    char* p = (char*)pVoid;
+    for (int i = 0; i < len; i++) SpiTransfer(*p++);
+    SpiChipSelect(1);
+}
+void FramRead(int address, int len, void* pVoid)
+{
+    if (address + len > FRAM_SIZE - 1 || address < 0)
+    {
+        Log("FramRead - Invalid FRAM address\r\n");
+        return;
+    }
+    SpiChipSelect(0);
+    SpiTransfer(READ);
+    SpiTransfer(address >> 8);
+    SpiTransfer(address & 0xFF);
+    char* p = (char*)pVoid;
+    for (int i = 0; i < len; i++) *p++ = SpiTransfer(0);
+    SpiChipSelect(1);
+}
+
+int FramLoad(int len, void* pValue, void* pDefault)
+{
+    int address = FramAllocate(len);
+    if (address >= 0) 
+    {
+        if (FramEmpty)
+        {
+            if (pDefault)
+            {
+                int defaultHasContent = 0;
+                char* pFrom = (char*)pDefault;
+                char* pTo   = (char*)pValue;
+                for (int i = 0; i < len; i++)
+                {
+                    if (*pFrom) defaultHasContent = 1;
+                    *pTo++ = *pFrom++;
+                }
+                if (defaultHasContent) FramWrite(address, len, pValue);
+            }
+            else //pDefault is NULL so zero the setting
+            {
+                memset(pValue, 0, len);
+            }
+        }
+        else
+        {
+            FramRead(address, len, pValue);
+        }
+    }
+    return address;
+}
diff -r 000000000000 -r e8f4aff306cd fram.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fram.h	Fri Apr 23 08:20:00 2021 +0000
@@ -0,0 +1,11 @@
+#include <stdbool.h>
+
+extern bool FramEmpty;
+extern int  FramUsed;
+extern int  FramInit(void);
+extern int  FramAllocate(int size);
+extern void FramWrite(int address, int len, void* pVoid);
+extern void FramRead (int address, int len, void* pVoid);
+extern int  FramLoad (int len, void* pValue, void* pDefault);
+
+#define FRAM_SIZE   8192
diff -r 000000000000 -r e8f4aff306cd spi.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spi.c	Fri Apr 23 08:20:00 2021 +0000
@@ -0,0 +1,55 @@
+#include "gpio.h"
+#include "log.h"
+
+#define CS_DIR FIO0DIR(6)
+#define CS_SET FIO0SET(6)
+#define CS_CLR FIO0CLR(6)
+
+//SSP1
+#define CR0     (*((volatile unsigned *) 0x40030000))
+#define CR1     (*((volatile unsigned *) 0x40030004))
+#define DR      (*((volatile unsigned *) 0x40030008))
+#define SR      (*((volatile unsigned *) 0x4003000C))
+#define CPSR    (*((volatile unsigned *) 0x40030010))
+
+void SpiInit(void)
+{
+    //Configure
+    CR0 |= 7 << 0; //3:0 8 bit transfer
+    CR0 |= 0 << 4; //5:4 SPI
+    CR0 |= 0 << 6; //7:6 Mode 0
+    CR0 |= 0 << 8; //divide by 1
+
+    //Set prescaler bps = PCLK / PS ==> PS = PCLK / bps ==> PS = 96/16 = 6
+    CPSR = 6; //Bit 0 must be 0. 6 ==> 16 bps which is within the 20MHz allowed by the FRAM
+    
+    //Select the function of the ssel pin: P0.6
+    CS_SET;     //Deselect the output == CS = 1
+    CS_DIR = 1; //Set the direction to 1 == output
+    
+    //Enable operation
+    CR1 |= 2; //Enable the SSP controller
+}
+void SpiChipSelect(int value)
+{
+    if (value) CS_SET;
+    else       CS_CLR;
+}
+void SpiWrite(char byte)
+{
+    DR = byte; //This loads the next frame in the TX FIFO
+}
+int  SpiBusy(void)
+{
+    return SR & 0x10; //bit 4 is BSY. This bit is 0 if the SSPn controller is idle, or 1 if it is currently sending/receiving a frame and/or the Tx FIFO is not empty.
+}
+char SpiRead(void)
+{
+    return DR & 0xFF; //This reads the oldest frame in the RX FIFO
+}
+char SpiTransfer(char byte)
+{
+    SpiWrite(byte);
+    while(SpiBusy()) /*spin until not busy, at 16 bits per us or 2 bytes per us should be only 48 operations*/;
+    return SpiRead();
+}
diff -r 000000000000 -r e8f4aff306cd spi.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spi.h	Fri Apr 23 08:20:00 2021 +0000
@@ -0,0 +1,6 @@
+extern void SpiInit(void);
+extern void SpiChipSelect(int value);
+extern void SpiWrite(char byte);
+extern int  SpiBusy(void);
+extern char SpiRead(void);
+extern char SpiTransfer(char byte);
\ No newline at end of file