From c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 29 Jun 2014 12:34:32 +0300 Subject: Add more board models --- boards/ek-lm4f232/qs-logger/flashstore.c | 625 +++++++++++++++++++++++++++++++ 1 file changed, 625 insertions(+) create mode 100644 boards/ek-lm4f232/qs-logger/flashstore.c (limited to 'boards/ek-lm4f232/qs-logger/flashstore.c') diff --git a/boards/ek-lm4f232/qs-logger/flashstore.c b/boards/ek-lm4f232/qs-logger/flashstore.c new file mode 100644 index 0000000..30cbcea --- /dev/null +++ b/boards/ek-lm4f232/qs-logger/flashstore.c @@ -0,0 +1,625 @@ +//***************************************************************************** +// +// flashstore.c - Data logger module to handle storage in flash. +// +// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#include +#include +#include +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "driverlib/flash.h" +#include "utils/ustdlib.h" +#include "qs-logger.h" +#include "usbstick.h" +#include "flashstore.h" + +//***************************************************************************** +// +// This module manages the storage of data logger data into flash memory. +// +//***************************************************************************** + +//***************************************************************************** +// +// Define the beginning and end of the flash storage area. You must make sure +// that this area is well clear of any space occupied by the application +// binary, and that this space is not used for any other purpose. +// The start and end addresses must be 1K aligned. The end address is +// exclusive - it is 1 value greater than the last valid location used for +// storage. +// +//***************************************************************************** +#define FLASH_STORE_START_ADDR 0x20000 +#define FLASH_STORE_END_ADDR 0x40000 + +//***************************************************************************** +// +// The next address in flash, that will be used for storing a data record. +// +//***************************************************************************** +static uint32_t g_ui32StoreAddr; + +//***************************************************************************** +// +// A buffer used to assemble a complete record of data prior to storing it +// in the flash. +// +//***************************************************************************** +static uint32_t g_pui32RecordBuf[32]; + +//***************************************************************************** +// +// Initializes the flash storage. This is a stub because there is nothing +// special to do. +// +//***************************************************************************** +void +FlashStoreInit(void) +{ +} + +//***************************************************************************** +// +// Saves data records that are stored in the flash to an externally connected +// USB memory storage device (USB stick). +// The flash memory is scanned for the presence of store data records. When +// records are found they are written in CSV format to the USB stick. This +// function assumes a non-corrupted storage area, and that any records, once +// found, are contiguous with all stored records. It will find the oldest +// record and start with that when storing. +// +//***************************************************************************** +int32_t +FlashStoreSave(void) +{ + uint32_t ui32Addr, ui32OldestRecord, ui32OldestSeconds, ui32Count, + ui32PartialCount; + tLogRecord *psRecord; + + // + // Initialize locals. + // + ui32OldestRecord = FLASH_STORE_START_ADDR; + ui32OldestSeconds = 0xFFFFFFFF; + + // + // Show a message to the user. + // + SetStatusText("SAVE", "SCANNING", "FLASH", 0); + + // + // Start at beginning of flash storage area + // + ui32Addr = FLASH_STORE_START_ADDR; + + // + // Search all of flash area checking every stored record. + // + while(ui32Addr < FLASH_STORE_END_ADDR) + { + // + // If a record signature is found, check for oldest record, then + // increment to the next record + // + if((HWREG(ui32Addr) & 0xFFFFFF00) == 0x53554100) + { + // + // Get a pointer to the data record (account for flash header word) + // + psRecord = (tLogRecord *)(ui32Addr + 4); + + // + // If the seconds in this record are older than any found so far + // then save the seconds value, and the address of this record + // + if(psRecord->ui32Seconds < ui32OldestSeconds) + { + ui32OldestSeconds = psRecord->ui32Seconds; + ui32OldestRecord = ui32Addr; + } + + // + // Advance the address to the next record. + // + ui32Addr += HWREG(ui32Addr) & 0xFF; + } + else + { + // + // A record was not found so just advance to the next location in + // flash + // + ui32Addr += 4; + } + } + + // + // If no "oldest" seconds was found, then there is no valid data stored + // + if(ui32OldestSeconds == 0xFFFFFFFF) + { + SetStatusText("SAVE", "NO RECORDS", "FOUND", "PRESS <"); + return(1); + } + + // + // Open the output file on the USB stick. It will return NULL if there + // was any problem. + // + if(!USBStickOpenLogFile(0)) + { + SetStatusText("SAVE", 0, "USB ERROR", "PRESS <"); + return(1); + } + + // + // Notify user we are saving data to USB + // + SetStatusText("SAVE", "SAVING", "TO USB", 0); + + // + // Start reading records from flash, start at the address of the oldest + // record, as found above. We scan through records, assuming the flash + // store is not corrupted. Continue scanning until a blank space is + // found which should indicate the end of recorded data, or until we + // have read all the records. + // + ui32Addr = ui32OldestRecord; + while(HWREG(ui32Addr) != 0xFFFFFFFF) + { + // + // If a record signature is found (which it should be), extract the + // record data and send it to USB stick. + // + if((HWREG(ui32Addr) & 0xFFFFFF00) == 0x53554100) + { + // + // Get byte count for this record + // + ui32Count = HWREG(ui32Addr) & 0xFF; + + // + // Adjust the count and the address to remove the flash header + // + ui32Count -= 4; + ui32Addr += 4; + + // + // Adjust for memory wrap + // + if(ui32Addr >= FLASH_STORE_END_ADDR) + { + ui32Addr = FLASH_STORE_START_ADDR; + } + + // + // If the contents of this record go past the end of the memory + // storage area, then perform a partial copy first. + // + ui32PartialCount = 0; + if((ui32Addr + ui32Count) >= FLASH_STORE_END_ADDR) + { + // + // Find how many bytes are left on this page + // + ui32PartialCount = FLASH_STORE_END_ADDR - ui32Addr; + + // + // Copy the portion until the end of memory store, adjust + // remaining count and address + // + memcpy(g_pui32RecordBuf, (void *)ui32Addr, ui32PartialCount); + ui32Count -= ui32PartialCount; + ui32Addr = FLASH_STORE_START_ADDR; + } + + // + // Copy entire record (or remaining part of record if memory wrap) + // into record buffer + // + memcpy(&g_pui32RecordBuf[ui32PartialCount / 4], (void *)ui32Addr, + ui32Count); + + // + // Update address pointer to next record + // + ui32Addr += ui32Count; + + // + // Now we have an entire data logger record copied from flash + // storage into a local (contiguous) memory buffer. Pass it + // to the USB file writing function to write the record to the + // USB stick. + // + USBStickWriteRecord((tLogRecord *)g_pui32RecordBuf); + } + else + { + // + // This should not happen, but it means we ended up in a non-blank + // location that is not the start of a record. In this case just + // advance through memory until either a blank location or another + // record is found. + // + // Increment to next word in flash, adjust for memory wrap. + // + ui32Addr += 4; + if(ui32Addr >= FLASH_STORE_END_ADDR) + { + ui32Addr = FLASH_STORE_START_ADDR; + } + } + } + + // + // Close the USB stick file so that any buffers will be flushed. + // + USBStickCloseFile(); + + // + // Inform user that save is complete. + // + SetStatusText("SAVE", "USB SAVE", "COMPLETE", "PRESS <"); + + // + // Return success + // + return(0); +} + +//***************************************************************************** +// +// This is called at the start of logging to prepare space in flash for +// storage of logged data. It searches for the first blank area in the +// flash storage to be used for storing records. +// +// If a starting address is specified then the search is skipped and it goes +// directly to the new address. If the starting address is 0, then it performs +// the search. +// +//***************************************************************************** +int32_t +FlashStoreOpenLogFile(uint32_t ui32StartAddr) +{ + uint32_t ui32Addr; + + // + // If a valid starting address is specified, then just use that and skip + // the search below. + // + if((ui32StartAddr >= FLASH_STORE_START_ADDR) && + (ui32StartAddr < FLASH_STORE_END_ADDR)) + { + g_ui32StoreAddr = ui32StartAddr; + return(0); + } + + // + // Start at beginning of flash storage area + // + ui32Addr = FLASH_STORE_START_ADDR; + + // + // Search until a blank is found or the end of flash storage area + // + while((HWREG(ui32Addr) != 0xFFFFFFFF) && (ui32Addr < FLASH_STORE_END_ADDR)) + { + // + // If a record signature is found, then increment to the next record + // + if((HWREG(ui32Addr) & 0xFFFFFF00) == 0x53554100) + { + ui32Addr += HWREG(ui32Addr) & 0xFF; + } + else + { + // + // Just advance to the next location in flash + // + ui32Addr += 4; + } + } + + // + // If we are at the end of flash that means no blank area was found. + // So reset to the beginning and erase the first page. + // + if(ui32Addr >= FLASH_STORE_END_ADDR) + { + ui32Addr = FLASH_STORE_START_ADDR; + FlashErase(ui32Addr); + } + + // + // When we reach here we either found a blank location, or made a new + // blank location by erasing the first page. + // To keep things simple we are making an assumption that the flash store + // is not corrupted and that the first blank location implies the start + // of a blank area suitable for storing data records. + // + g_ui32StoreAddr = ui32Addr; + + // + // Return success indication to caller + // + return(0); +} + +//***************************************************************************** +// +// This is called each time there is a new data record to log to the flash +// storage area. A simple algorithm is used which rotates programming +// data log records through an area of flash. It is assumed that the current +// page is blank. Records are stored on the current page until a page +// boundary is crossed. If the page boundary is crossed and the new page +// is not blank (testing only the first location), then the new page is +// erased. Finally the entire record is programmed into flash and the +// storage pointers are updated. +// +// While storing and when crossing to a new page, if the flash page is not +// blank it is erased. So this algorithm overwrites old data. +// +// The data is stored in flash as a record, with a flash header prepended, +// and with the record length padded to be a multiple of 4 bytes. The flash +// header is a 3-byte magic number and one byte of record length. +// +//***************************************************************************** +int32_t +FlashStoreWriteRecord(tLogRecord *psRecord) +{ + uint32_t ui32Idx, ui32ItemCount, *pui32Record; + + // + // Check the arguments + // + ASSERT(psRecord); + if(!psRecord) + { + return(1); + } + + // + // Determine how many channels are to be logged + // + ui32Idx = psRecord->ui16ItemMask; + ui32ItemCount = 0; + while(ui32Idx) + { + if(ui32Idx & 1) + { + ui32ItemCount++; + } + ui32Idx >>= 1; + } + + // + // Add 16-bit count equivalent of record header, time stamp, and + // selected items mask. This is the total number of 16 bit words + // of the record. + // + ui32ItemCount += 6; + + // + // Convert the count to bytes, be sure to pad to 32-bit alignment. + // + ui32ItemCount = ((ui32ItemCount * 2) + 3) & ~3; + + // + // Create the flash record header, which is a 3-byte signature and a + // one byte count of bytes in the record. Save it at the beginning + // of the write buffer. + // + ui32Idx = 0x53554100 | (ui32ItemCount & 0xFF); + g_pui32RecordBuf[0] = ui32Idx; + + // + // Copy the rest of the record to the buffer, and get a pointer to + // the buffer. + // + memcpy(&g_pui32RecordBuf[1], psRecord, ui32ItemCount - 4); + pui32Record = g_pui32RecordBuf; + + // + // Check to see if the record is going to cross a page boundary. + // + if(((g_ui32StoreAddr & 0x3FF) + ui32ItemCount) > 0x3FF) + { + // + // Find number of bytes remaining on this page + // + ui32Idx = 0x400 - (g_ui32StoreAddr & 0x3FF); + + // + // Program part of the record on the space remaining on the current + // page + // + FlashProgram(pui32Record, g_ui32StoreAddr, ui32Idx); + + // + // Increment the store address by the amount just written, which + // should make the new store address be at the beginning of the next + // flash page. + // + g_ui32StoreAddr += ui32Idx; + + // + // Adjust the remaining bytes to program, and the pointer to the + // remainder of the record data. + // + ui32ItemCount -= ui32Idx; + pui32Record = &g_pui32RecordBuf[ui32Idx / 4]; + + // + // Check to see if the new page is past the end of store and adjust + // + if(g_ui32StoreAddr >= FLASH_STORE_END_ADDR) + { + g_ui32StoreAddr = FLASH_STORE_START_ADDR; + } + + // + // If new page is not blank, then erase it + // + if(HWREG(g_ui32StoreAddr) != 0xFFFFFFFF) + { + FlashErase(g_ui32StoreAddr); + } + } + + // + // Now program the remaining part of the record (if we crossed a page + // boundary above) or the full record to the current location in flash + // + FlashProgram(pui32Record, g_ui32StoreAddr, ui32ItemCount); + + // + // Increment the storage address to the next location. + // + g_ui32StoreAddr += ui32ItemCount; + + // + // Return success indication to caller. + // + return(0); +} + +//***************************************************************************** +// +// Return the current address being used for storing records. +// +//***************************************************************************** +uint32_t +FlashStoreGetAddr(void) +{ + return(g_ui32StoreAddr); +} + +//***************************************************************************** +// +// Erase the data storage area of flash. +// +//***************************************************************************** +void +FlashStoreErase(void) +{ + uint32_t ui32Addr; + + // + // Inform user we are erasing + // + SetStatusText("ERASE", 0, "ERASING", 0); + + // + // Loop through entire storage area and erase each page. + // + for(ui32Addr = FLASH_STORE_START_ADDR; ui32Addr < FLASH_STORE_END_ADDR; + ui32Addr += 0x400) + { + FlashErase(ui32Addr); + } + + // + // Inform user the erase is done. + // + SetStatusText("SAVE", "ERASE", "COMPLETE", "PRESS <"); +} + +//***************************************************************************** +// +// Determine if the flash block that contains the address is blank. +// +//***************************************************************************** +static int32_t +IsBlockFree(uint32_t ui32BaseAddr) +{ + uint32_t ui32Addr; + + // + // Make sure we start at the beginning of a 1K block + // + ui32BaseAddr &= ~0x3FF; + + // + // Loop through every address in this block and test if it is blank. + // + for(ui32Addr = 0; ui32Addr < 0x400; ui32Addr += 4) + { + if(HWREG(ui32BaseAddr + ui32Addr) != 0xFFFFFFFF) + { + // + // Found a non-blank location, so return indication that block + // is not free. + // + return(0); + } + } + + // + // If we made it to here then every location in this block is erased, + // so return indication that the block is free. + // + return(1); +} + +//***************************************************************************** +// +// Report to the user the amount of free space and used space in the data +// storage area. +// +//***************************************************************************** +void +FlashStoreReport(void) +{ + uint32_t ui32Addr, ui32FreeBlocks, ui32UsedBlocks = 0; + static char pcBufFree[16], pcBufUsed[16]; + + // + // Initialize locals. + // + ui32FreeBlocks = 0; + ui32UsedBlocks = 0; + + // + // Loop through each block of the storage area and count how many blocks + // are free and non-free. + // + for(ui32Addr = FLASH_STORE_START_ADDR; ui32Addr < FLASH_STORE_END_ADDR; + ui32Addr += 0x400) + { + if(IsBlockFree(ui32Addr)) + { + ui32FreeBlocks++; + } + else + { + ui32UsedBlocks++; + } + } + + // + // Report the result to the user via a status display screen. + // + usnprintf(pcBufFree, sizeof(pcBufFree), "FREE: %3uK", ui32FreeBlocks); + usnprintf(pcBufUsed, sizeof(pcBufUsed), "USED: %3uK", ui32UsedBlocks); + SetStatusText("FREE FLASH", pcBufFree, pcBufUsed, "PRESS <"); +} -- cgit v1.3.1