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();
}