Electric Locomotive control system. Touch screen driver control, includes regenerative braking, drives 4 brushless motors, displays speed MPH, system volts and power
Dependencies: BSP_DISCO_F746NG FastPWM LCD_DISCO_F746NG SD_DISCO_F746NG TS_DISCO_F746NG mbed
Diff: sd_card.cpp
- Revision:
- 1:8ef34deb5177
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd_card.cpp Mon Nov 13 09:53:00 2017 +0000 @@ -0,0 +1,204 @@ +#include "mbed.h" +#include "Electric_Loco.h" +#include "SD_DISCO_F746NG.h" +/* +SD card used only to keep log of total distance travelled. +Odometer is trivial. +This file treats SD card as random access memory. +A better implementation would use library functions for FAT file system etc. + +May revisit this. + +*/ +SD_DISCO_F746NG sd; +extern Serial pc; +extern uint32_t historic_distance; +extern uint32_t get_pulse_total () ; + +static const int + SD_BLOCKSIZE = 512; /* SD card data Block Size in Bytes */ +// Assume SD card size is 4Gbyte, might be 8 Gbyte +// Then can use 8388608 blocks (8 * 1024 * 1024) + +uint64_t SD_blockptr = 0; +uint32_t SDBuffer[(SD_BLOCKSIZE >> 2)]; // = space for (512 / 4) uint32_t +uint8_t SD_state = SD_OK, sd_jf = 0; + +static const uint64_t GIGAB = 1024 * 1024 * 1024; +//static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 4; // software drives SD up to 4Gbyte only - 8 M block +static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 2; // software drives SD up to 4Gbyte only - 8 M block +// If data logger takes 2 minutes to fill 1 block, a 4G card takes 32 years run-time to fill +// If system generates approx 320 pulses per metre travelled, max distance recordable in uint32_t is 65536 * 65536 / 320 = 13421.772 km +bool sd_error () { // Test and Clear error code sd_jf, return true if any error bits set, false on 0 + bool retval = false; + if (sd_jf != 0) { + retval = true; + sd_jf = 0; + } + return retval; +} + +bool check_SD_block_clear (uint32_t block) { + uint32_t b[(SD_BLOCKSIZE >> 2)]; + SD_state = sd.ReadBlocks(b, (uint64_t)(SD_BLOCKSIZE * block), SD_BLOCKSIZE, 1); + if(SD_state != SD_OK) { + sd_jf = 1; + pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block); + return false; + } + for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++) + if (b[i] != 0) + return false; + return true; +} + +bool read_SD_state () { + if (SD_state == SD_OK) + return true; + return false; +} +/*bool erase_block (uint32_t block2erase) { + uint64_t addr = SD_BLOCKSIZE * (uint64_t)block2erase; + SD_state = sd.Erase(addr, addr + SD_BLOCKSIZE); + if (SD_state != SD_OK) { + sd_jf = 1; // Assert error flag + pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block2erase); + return false; + } + return check_SD_block_clear (block2erase); +}*/ + +bool SD_find_next_clear_block (uint64_t * blok) { // Successive approximation algorithm to quickly find next vacant SD card 512 byte block + uint64_t toaddsub = SDBLOCKS / 2, stab = SDBLOCKS - 1; + pc.printf ("At SD_find_next_clear_block \r\n"); + while (toaddsub) { + pc.printf ("stab = %lld, toadsub = %lld\r\n", stab, toaddsub); // lld for long long int + bool clear_block = true; + SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * stab, SD_BLOCKSIZE, 1); + if(SD_state != SD_OK) { + sd_jf = 1; + pc.printf ("SD error in SD_find_next_clear_block, returning -1\r\n"); + return false; + } + for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++) { + if (SDBuffer[i] != 0) { + clear_block = false; + pc.printf ("Buff at %d contains %x\r\n", i, SDBuffer[i]); + i = SD_BLOCKSIZE; // to exit loop + } + } + if (clear_block) + stab -= toaddsub; + else + stab += toaddsub; + toaddsub >>= 1; + } + if (!check_SD_block_clear(stab)) + stab++; + if (sd_error()) { // sd_error() tests and clears error bits + pc.printf ("check_SD_block_clear(%ld)returned ERROR in SD_find_next_clear_block\r\n", stab); + sd_jf = 1; // reassert error flag + return false; + } + pc.printf ("Completed find_next, stab = %d\r\n", stab); + *blok = stab; // block number of next free block + return true; +} + +bool SD_card_erase_all (void) { // assumes sd card is 4 Gbyte, erases 4 Gbyte. Called from CLI + uint64_t EndAddr = GIGAB * 4, + StartAddr = 0LL; + sd_jf = 0; + pc.printf ("Erasing SD card ... "); + // uint8_t Erase(uint64_t StartAddr, uint64_t EndAddr); + SD_state = sd.Erase(StartAddr, EndAddr); + if (SD_state != SD_OK) { + pc.printf ("SD_card_erase_all FAILED\r\n"); + sd_jf = 1; + return false; + } + pc.printf ("no error detected\r\n"); + return true; +} + + +bool mainSDtest() +{ + SD_state = sd.Init(); + if(SD_state != SD_OK) { + pc.printf ("sd.Init set SD_state to %0x\r\n", SD_state); + if(SD_state == MSD_ERROR_SD_NOT_PRESENT) { + pc.printf("SD shall be inserted before running test\r\n"); + } else { + pc.printf("SD Initialization : FAIL.\r\n"); + } + pc.printf("SD Test Aborted.\r\n"); + return false; + } +// else { // SD_state is SD_OK + pc.printf("SD Initialization : OK.\r\n"); + + + +// SD_card_erase_all(); +// if (sd_error()) +// pc.printf ("SD_card_erase_all() reports ERROR"); + + + + SD_find_next_clear_block(& SD_blockptr); + pc.printf ("SD_find_next_clear_block returned %lld\r\n\n\n", SD_blockptr); + if (sd_error()) { + pc.printf ("***** ERROR returned from SD_find_next_clear_block ***** SD ops aborted\r\n"); + return false; + } + pc.printf("SD_find_next_clear_block() returned %ld\r\n", SD_blockptr); + if (SD_blockptr < 1) { + pc.printf ("Looks like card newly erased, SD_blockptr value of %d\r\n", SD_blockptr); + SD_blockptr = 0; + historic_distance = 0; + } + else { + SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * (SD_blockptr - 1), SD_BLOCKSIZE, 1); + if (SD_state != SD_OK) { + pc.printf ("Error reading last block from SD block %d\r\n", SD_blockptr - 1); + return false; + } + for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++) + pc.printf ("%lx\t", SDBuffer[i]); + historic_distance = SDBuffer[(SD_BLOCKSIZE >> 2) - 1]; + pc.printf ("\r\nAbove, data read from last filled SD block %lld, using historic_distance = %lx\r\n", SD_blockptr - 1, historic_distance); + } + if (SD_blockptr > 2) { + for (int i = SD_blockptr - 2; i < SD_blockptr + 2; i++) { + pc.printf ("check_SD_block_clear (%d) ", i); + if (check_SD_block_clear(i)) + pc.printf ("block %ld is CLEAR\r\n", i); + else + pc.printf ("block %ld is NOT clear\r\n", i); + if (sd_error()) { + pc.printf ("ERROR from check_SD_block_clear ()\r\n"); + } + } + } + return true; +} + +void update_SD_card () { // Hall pulse total updated once per sec and saved in blocks of 128 to SD card + static int index = 0; + static uint32_t buff[(SD_BLOCKSIZE >> 2) + 2]; +// buff[index++] = speed.pulse_total(); // pulse_total for all time, add this to buffer to write to SD + buff[index++] = get_pulse_total(); // pulse_total for all time, add this to buffer to write to SD + if (index >= (SD_BLOCKSIZE >> 2)) { + pc.printf ("Writing new SD block %d ... ", SD_blockptr); + SD_state = sd.WriteBlocks(buff, SD_BLOCKSIZE * SD_blockptr, SD_BLOCKSIZE, 1); + SD_blockptr++; + if (SD_state == SD_OK) + pc.printf ("OK, distance %d\r\n", buff[index - 1] / (int)PULSES_PER_METRE); + else + pc.printf ("ERROR\r\n"); + index = 0; + } +} + +