A module to store data on a fram.
Dependents: oldheating motorhome heating
fram.c@0:e8f4aff306cd, 2021-04-23 (annotated)
- Committer:
- andrewboyson
- Date:
- Fri Apr 23 08:20:00 2021 +0000
- Revision:
- 0:e8f4aff306cd
Stores data on the FRAM
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 0:e8f4aff306cd | 1 | #include <string.h> |
andrewboyson | 0:e8f4aff306cd | 2 | #include <stdbool.h> |
andrewboyson | 0:e8f4aff306cd | 3 | |
andrewboyson | 0:e8f4aff306cd | 4 | #include "spi.h" |
andrewboyson | 0:e8f4aff306cd | 5 | #include "log.h" |
andrewboyson | 0:e8f4aff306cd | 6 | #include "fram.h" |
andrewboyson | 0:e8f4aff306cd | 7 | |
andrewboyson | 0:e8f4aff306cd | 8 | #define WREN 0x06 // Set Write Enable Latch 0000 0110B |
andrewboyson | 0:e8f4aff306cd | 9 | #define WRDI 0x04 // Reset Write Enable Latch 0000 0100B |
andrewboyson | 0:e8f4aff306cd | 10 | #define RDSR 0x05 // Read Status Register 0000 0101B |
andrewboyson | 0:e8f4aff306cd | 11 | #define WRSR 0x01 // Write Status Register 0000 0001B |
andrewboyson | 0:e8f4aff306cd | 12 | #define READ 0x03 // Read Memory Code 0000 0011B |
andrewboyson | 0:e8f4aff306cd | 13 | #define WRITE 0x02 // Write Memory Code 0000 0010B |
andrewboyson | 0:e8f4aff306cd | 14 | #define RDID 0x9F // Read Device ID 1001 1111B |
andrewboyson | 0:e8f4aff306cd | 15 | |
andrewboyson | 0:e8f4aff306cd | 16 | #define FRAM_ID 0x047f0302 |
andrewboyson | 0:e8f4aff306cd | 17 | #define FRAM_MAGIC 42 //Magic number to show that the FRAM has been intialised |
andrewboyson | 0:e8f4aff306cd | 18 | |
andrewboyson | 0:e8f4aff306cd | 19 | bool FramEmpty; //Set in FramInit |
andrewboyson | 0:e8f4aff306cd | 20 | int FramUsed; //Initialised in FramInit and used by FramAllocate to remember the next available location |
andrewboyson | 0:e8f4aff306cd | 21 | |
andrewboyson | 0:e8f4aff306cd | 22 | int FramAllocate(int size) //Allocates a number of bytes in FRAM |
andrewboyson | 0:e8f4aff306cd | 23 | { |
andrewboyson | 0:e8f4aff306cd | 24 | int start = FramUsed; |
andrewboyson | 0:e8f4aff306cd | 25 | int used = FramUsed + size; |
andrewboyson | 0:e8f4aff306cd | 26 | if (used > FRAM_SIZE - 1) |
andrewboyson | 0:e8f4aff306cd | 27 | { |
andrewboyson | 0:e8f4aff306cd | 28 | Log("FramAllocate - No more room in FRAM\r\n"); |
andrewboyson | 0:e8f4aff306cd | 29 | return -1; |
andrewboyson | 0:e8f4aff306cd | 30 | } |
andrewboyson | 0:e8f4aff306cd | 31 | FramUsed = used; |
andrewboyson | 0:e8f4aff306cd | 32 | return start; |
andrewboyson | 0:e8f4aff306cd | 33 | } |
andrewboyson | 0:e8f4aff306cd | 34 | int FramInit() |
andrewboyson | 0:e8f4aff306cd | 35 | { |
andrewboyson | 0:e8f4aff306cd | 36 | //Configure SPI |
andrewboyson | 0:e8f4aff306cd | 37 | SpiInit(); |
andrewboyson | 0:e8f4aff306cd | 38 | |
andrewboyson | 0:e8f4aff306cd | 39 | //Check if the FRAM is connected and working properly |
andrewboyson | 0:e8f4aff306cd | 40 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 41 | SpiTransfer(RDID); |
andrewboyson | 0:e8f4aff306cd | 42 | int id = 0; |
andrewboyson | 0:e8f4aff306cd | 43 | id = (id << 8) + SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 44 | id = (id << 8) + SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 45 | id = (id << 8) + SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 46 | id = (id << 8) + SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 47 | SpiChipSelect(1); |
andrewboyson | 0:e8f4aff306cd | 48 | if (id != FRAM_ID) |
andrewboyson | 0:e8f4aff306cd | 49 | { |
andrewboyson | 0:e8f4aff306cd | 50 | LogF("FramInit - Expected FRAM id %08x but got %08x\r\n", FRAM_ID, id); |
andrewboyson | 0:e8f4aff306cd | 51 | return -1; |
andrewboyson | 0:e8f4aff306cd | 52 | } |
andrewboyson | 0:e8f4aff306cd | 53 | |
andrewboyson | 0:e8f4aff306cd | 54 | //Check the first byte to see if the FRAM is initialised and zero if not |
andrewboyson | 0:e8f4aff306cd | 55 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 56 | SpiTransfer(READ); |
andrewboyson | 0:e8f4aff306cd | 57 | SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 58 | SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 59 | char magic = SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 60 | SpiChipSelect(1); |
andrewboyson | 0:e8f4aff306cd | 61 | FramEmpty = magic != FRAM_MAGIC; |
andrewboyson | 0:e8f4aff306cd | 62 | if (FramEmpty) |
andrewboyson | 0:e8f4aff306cd | 63 | { |
andrewboyson | 0:e8f4aff306cd | 64 | LogF("FramInit - Byte 0 value %d is not the magic value %d so initialising FRAM to zero\r\n", magic, FRAM_MAGIC); |
andrewboyson | 0:e8f4aff306cd | 65 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 66 | SpiTransfer(WREN); |
andrewboyson | 0:e8f4aff306cd | 67 | SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); SpiChipSelect(1); |
andrewboyson | 0:e8f4aff306cd | 68 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 69 | SpiTransfer(WRITE); |
andrewboyson | 0:e8f4aff306cd | 70 | SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 71 | SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 72 | SpiTransfer(FRAM_MAGIC); //Set the magic number in byte 0 |
andrewboyson | 0:e8f4aff306cd | 73 | for(int i = 1; i < FRAM_SIZE; i++) SpiTransfer(0); //Zero all other locations |
andrewboyson | 0:e8f4aff306cd | 74 | SpiChipSelect(1); |
andrewboyson | 0:e8f4aff306cd | 75 | } |
andrewboyson | 0:e8f4aff306cd | 76 | FramUsed = 1; //Set the next available location to one past the byte used for the magic number |
andrewboyson | 0:e8f4aff306cd | 77 | return 0; |
andrewboyson | 0:e8f4aff306cd | 78 | } |
andrewboyson | 0:e8f4aff306cd | 79 | void FramWrite(int address, int len, void* pVoid) |
andrewboyson | 0:e8f4aff306cd | 80 | { |
andrewboyson | 0:e8f4aff306cd | 81 | if (address + len > FRAM_SIZE - 1 || address < 0) |
andrewboyson | 0:e8f4aff306cd | 82 | { |
andrewboyson | 0:e8f4aff306cd | 83 | Log("FramWrite - Invalid FRAM address\r\n"); |
andrewboyson | 0:e8f4aff306cd | 84 | return; |
andrewboyson | 0:e8f4aff306cd | 85 | } |
andrewboyson | 0:e8f4aff306cd | 86 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 87 | SpiTransfer(WREN); |
andrewboyson | 0:e8f4aff306cd | 88 | 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 |
andrewboyson | 0:e8f4aff306cd | 89 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 90 | SpiTransfer(WRITE); |
andrewboyson | 0:e8f4aff306cd | 91 | SpiTransfer(address >> 8); |
andrewboyson | 0:e8f4aff306cd | 92 | SpiTransfer(address & 0xFF); |
andrewboyson | 0:e8f4aff306cd | 93 | char* p = (char*)pVoid; |
andrewboyson | 0:e8f4aff306cd | 94 | for (int i = 0; i < len; i++) SpiTransfer(*p++); |
andrewboyson | 0:e8f4aff306cd | 95 | SpiChipSelect(1); |
andrewboyson | 0:e8f4aff306cd | 96 | } |
andrewboyson | 0:e8f4aff306cd | 97 | void FramRead(int address, int len, void* pVoid) |
andrewboyson | 0:e8f4aff306cd | 98 | { |
andrewboyson | 0:e8f4aff306cd | 99 | if (address + len > FRAM_SIZE - 1 || address < 0) |
andrewboyson | 0:e8f4aff306cd | 100 | { |
andrewboyson | 0:e8f4aff306cd | 101 | Log("FramRead - Invalid FRAM address\r\n"); |
andrewboyson | 0:e8f4aff306cd | 102 | return; |
andrewboyson | 0:e8f4aff306cd | 103 | } |
andrewboyson | 0:e8f4aff306cd | 104 | SpiChipSelect(0); |
andrewboyson | 0:e8f4aff306cd | 105 | SpiTransfer(READ); |
andrewboyson | 0:e8f4aff306cd | 106 | SpiTransfer(address >> 8); |
andrewboyson | 0:e8f4aff306cd | 107 | SpiTransfer(address & 0xFF); |
andrewboyson | 0:e8f4aff306cd | 108 | char* p = (char*)pVoid; |
andrewboyson | 0:e8f4aff306cd | 109 | for (int i = 0; i < len; i++) *p++ = SpiTransfer(0); |
andrewboyson | 0:e8f4aff306cd | 110 | SpiChipSelect(1); |
andrewboyson | 0:e8f4aff306cd | 111 | } |
andrewboyson | 0:e8f4aff306cd | 112 | |
andrewboyson | 0:e8f4aff306cd | 113 | int FramLoad(int len, void* pValue, void* pDefault) |
andrewboyson | 0:e8f4aff306cd | 114 | { |
andrewboyson | 0:e8f4aff306cd | 115 | int address = FramAllocate(len); |
andrewboyson | 0:e8f4aff306cd | 116 | if (address >= 0) |
andrewboyson | 0:e8f4aff306cd | 117 | { |
andrewboyson | 0:e8f4aff306cd | 118 | if (FramEmpty) |
andrewboyson | 0:e8f4aff306cd | 119 | { |
andrewboyson | 0:e8f4aff306cd | 120 | if (pDefault) |
andrewboyson | 0:e8f4aff306cd | 121 | { |
andrewboyson | 0:e8f4aff306cd | 122 | int defaultHasContent = 0; |
andrewboyson | 0:e8f4aff306cd | 123 | char* pFrom = (char*)pDefault; |
andrewboyson | 0:e8f4aff306cd | 124 | char* pTo = (char*)pValue; |
andrewboyson | 0:e8f4aff306cd | 125 | for (int i = 0; i < len; i++) |
andrewboyson | 0:e8f4aff306cd | 126 | { |
andrewboyson | 0:e8f4aff306cd | 127 | if (*pFrom) defaultHasContent = 1; |
andrewboyson | 0:e8f4aff306cd | 128 | *pTo++ = *pFrom++; |
andrewboyson | 0:e8f4aff306cd | 129 | } |
andrewboyson | 0:e8f4aff306cd | 130 | if (defaultHasContent) FramWrite(address, len, pValue); |
andrewboyson | 0:e8f4aff306cd | 131 | } |
andrewboyson | 0:e8f4aff306cd | 132 | else //pDefault is NULL so zero the setting |
andrewboyson | 0:e8f4aff306cd | 133 | { |
andrewboyson | 0:e8f4aff306cd | 134 | memset(pValue, 0, len); |
andrewboyson | 0:e8f4aff306cd | 135 | } |
andrewboyson | 0:e8f4aff306cd | 136 | } |
andrewboyson | 0:e8f4aff306cd | 137 | else |
andrewboyson | 0:e8f4aff306cd | 138 | { |
andrewboyson | 0:e8f4aff306cd | 139 | FramRead(address, len, pValue); |
andrewboyson | 0:e8f4aff306cd | 140 | } |
andrewboyson | 0:e8f4aff306cd | 141 | } |
andrewboyson | 0:e8f4aff306cd | 142 | return address; |
andrewboyson | 0:e8f4aff306cd | 143 | } |