Touch screen drivers control dashboard for miniature locomotive. Features meters for speed, volts, power. Switches for lights, horns. Drives multiple STM3_ESC brushless motor controllers for complete brushless loco system as used in "The Brute" - www.jons-workshop.com

Dependencies:   TS_DISCO_F746NG mbed Servo LCD_DISCO_F746NG BSP_DISCO_F746NG QSPI_DISCO_F746NG AsyncSerial FastPWM

qspi_mem.cpp

Committer:
JonFreeman
Date:
2019-03-04
Revision:
14:6bcec5ac21ca
Parent:
12:a25bdf135348

File content as of revision 14:6bcec5ac21ca:

#include "mbed.h"
#include "Electric_Loco.h"

#include "QSPI_DISCO_F746NG.h"

extern  error_handling_Jan_2019   Controller_Error    ;

struct  log_element {
    uint32_t    pulsetot;   //  Total distance ever in metres
    uint16_t    powerW;     //  during previous second
    uint16_t    volts;      //  during previous second
}   ;

static  const   int START_BANK  = 97;    //  Which 4k segment to start at
static  const   int BANKS_4K    = 4;  //  Numof 4k byte pages used to store recent records

QSPI_DISCO_F746NG qspi;
extern  Serial pc;
//extern  uint32_t    historic_distance;    no longer exkists Apr 2018

    QSPI_Info pQSPI_Info;

bool    qspimemcheck    ()  {
    qspi.GetInfo(&pQSPI_Info);
    if ((pQSPI_Info.FlashSize          != N25Q128A_FLASH_SIZE) ||
        (pQSPI_Info.EraseSectorSize    != N25Q128A_SUBSECTOR_SIZE) || 
        (pQSPI_Info.ProgPageSize       != N25Q128A_PAGE_SIZE) ||
        (pQSPI_Info.EraseSectorsNumber != N25Q128A_SUBSECTOR_SIZE) ||
        (pQSPI_Info.ProgPagesNumber    != N25Q128A_SECTOR_SIZE))
    {
      error("Get informations FAILED\r\n");
      return    false;  //  Controller_Error.set gets called from main    ;
    }
    else
    {
/*        pc.printf("Get N25Q128A QSPI mem informations PASSED\r\n");
        pc.printf   ("FLASH_SIZE\t\t%d\r\n", N25Q128A_FLASH_SIZE);
        pc.printf   ("ERASE_SECTOR_SIZE\t%d\r\n", N25Q128A_SUBSECTOR_SIZE);
        pc.printf   ("PROG_PAGE_SIZE\t\t%d\r\n", N25Q128A_PAGE_SIZE);
        pc.printf   ("Erase sectors number\t%d\r\n", N25Q128A_SUBSECTOR_SIZE);
        pc.printf   ("N25Q128A_SECTOR_SIZE\t%d\r\n", N25Q128A_SECTOR_SIZE); */
        return    true;
    }
}

bool    test_qspi   ()  {
    if  ((qspi.Init() == QSPI_OK) && (qspimemcheck    ()))
        return  true;
    return  false;
}

void    show_bank   (uint32_t    bank)   {
    uint8_t bu[4096];
    struct  log_element * p = (log_element *)bu;
    if  (qspi.Read(bu, bank << 12, 4096) != QSPI_OK)  {
        pc.printf   ("Error reading qspi mem in show_bank\r\n");
        Controller_Error.set    (FAULT_QSPI, 1);
        return  ;
    }
    pc.printf   ("Listing records in bank %d\r\n", bank);
    for (int i = 0; i < 4095 / sizeof(struct log_element); i++) {
        pc.printf   ("p->pulsetot%ld, powerW %d, volts %d, addr %lx\r\n", p->pulsetot, p->powerW, p->volts, (uint32_t)p++);
    }
}

void    show_all_banks  ();
void    show_all_banks  ()  {
    for (int bank = START_BANK; bank < START_BANK + BANKS_4K; bank++)
        show_bank   (bank);
}

class   distance_measurement {
    uint32_t    total_distance; //  Replaces historic_distance from previous iterations
    uint32_t    bank;
    uint32_t    ptr;
    uint8_t     buff[4096];     //  Reqd qspi ram 4k at a time into here

    bool        test_element_free  (uint8_t* p)   ;
    bool        test_bank_free  (uint32_t addr)  ;
    bool        test_buff_free  ()  ;
public:
    bool        zero    ()  ;
    uint32_t    out ()  ;
    bool        update  (uint32_t pulsetot, uint16_t pow, uint16_t volt)  ;

    distance_measurement () {   //  Constructor
        uint32_t    obank = 0, optr = 0, lptr = 0;
        bool    free_elem_found = false;
        qspi.Init   ();

        bank = START_BANK;
        while   (bank < START_BANK + BANKS_4K && !free_elem_found)    {
            if  (qspi.Read(buff, bank << 12, 4096) != QSPI_OK)  {
                Controller_Error.set    (FAULT_QSPI, 1);
//                pc.printf   ("Error reading qspi mem\r\n");
            }
            for (ptr = 0; !free_elem_found && ptr < 4096; ptr += sizeof(struct log_element)) {
                free_elem_found = test_element_free  (&buff[ptr]);
                if  (free_elem_found)   {
                    obank = bank;
                    optr = ptr;
//                    pc.printf   ("Found free element at bank %d, ptr %x\r\n", bank, ptr);
                }
                else    {   //  Not free element found
                    lptr = ptr;
                }
            }
            bank++;
        }
        bank = obank;
        ptr = optr;
        struct  log_element * p = (log_element *)(buff + lptr);

//        historic_distance = p->pulsetot;  //  This needs replacing
        total_distance = p->pulsetot;   //  New May 2018, total_distance is metres. Update info arrives in mm.

//        pc.printf   ("Constructor found free elem at bank %d, position %d, previous total %ld, volts %.3f\r\n", bank, ptr, p->pulsetot, ((double)p->volts) / 500.0);
    }   //  endof constructor
}   odometer;


bool    distance_measurement::test_element_free  (uint8_t* p)  {
    for (int i = 0; i < sizeof(log_element); i++)
        if  (*(p + i) != 0xff)
            return  false;
    return  true;
}

bool    distance_measurement::test_buff_free  ()  {
    for (int i = 0; i < 4096; i++)
        if  (buff[i] != 0xff)
            return  false;
    return  true;
}

bool    distance_measurement::test_bank_free  (uint32_t addr)  {
    if  (qspi.Read   (buff, addr & 0xfffff000, 4096) != QSPI_OK)   {
        pc.printf   ("Read error in test_bank_free\r\n");
        return  false;
    }
    return  test_buff_free  ();
}

bool    distance_measurement::zero  ()  {
    bool    rv = true;
    total_distance = 0;
    for (int i = START_BANK; i < START_BANK + BANKS_4K; i++)    {
        if  (qspi.Erase_Block(i << 12) != QSPI_OK)  {
            pc.printf   ("Error zeroing odometer!\r\n");
            rv = false;
        }
        if  (!test_bank_free    (i << 12))
            pc.printf   ("Bank [%d] not freed in zero\r\n", i);
        else
            pc.printf   ("Cleared bank [%d] in zero\r\n", i);
    }
    bank = START_BANK;
    ptr = 0;
    return  rv;
}

bool    distance_measurement::update  (uint32_t new_metres_travelled, uint16_t powr, uint16_t volt)  {
    bool    rv = true;
    total_distance += new_metres_travelled;
    struct  log_element d;
    d.pulsetot   = total_distance;
    d.powerW     = powr;
    d.volts      = volt;
    uint32_t    addr = ptr + (bank << 12);
    if  (qspi.Write  ((uint8_t*)&d, addr, sizeof(struct log_element)) != QSPI_OK) {
        pc.printf   ("Write error in odometer update\r\n");
        qspi.Init();    //  Attempt error recovery
        return  false;
    }
    ptr += sizeof(struct log_element);
    if  (ptr >= 4096)   {
        ptr -= 4096;
        bank++;
        if  (bank >= START_BANK + BANKS_4K)
            bank = START_BANK;
        //erase bank
        pc.printf   ("About to erase bank %d\r\n", bank);
        if  (qspi.Erase_Block(bank << 12) != QSPI_OK)  {
            pc.printf   ("Erase error in odometer update\r\n");
            rv = false;
        }
    }
    return  rv;
}

uint32_t    distance_measurement::out  ()    {
    return  total_distance;
}


bool    odometer_zero   ()  ;   //  Returns true on success
bool    odometer_zero   ()  {   //  Returns true on success
    return  odometer.zero   ();
}

bool    odometer_update  (uint32_t pulsetot, uint16_t pow, uint16_t volt)  ;   //  Hall pulse total updated once per sec and saved in blocks of 4096 bytes on QSPI onboard memory
bool    odometer_update  (uint32_t pulsetot, uint16_t pow, uint16_t volt)  {   //  Hall pulse total updated once per sec and saved in blocks of 4096 bytes on QSPI onboard memory
    return  odometer.update (pulsetot, pow, volt);
}

uint32_t    odometer_out  ()    {
    return  odometer.out();
}