diff --git a/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp b/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp index 4ff2a5cedc16679cd685f9c1e3ed38760cd40411..6e1fff82d3e68b50fc1e62eefbfe82e763aa79f1 100644 --- a/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp +++ b/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp @@ -75,7 +75,7 @@ void QSPI::init() RCC_SYNC(); - Thread::sleep(200); + Thread::sleep(1); // abort possible ongoing command QUADSPI->CR |= QUADSPI_CR_ABORT; @@ -128,8 +128,8 @@ void QSPI::abort_reset() // reset configuration register QUADSPI->CCR = 0; - // transfer flag (TCF) will reset automatically if a transaction has been - // aborted. + // transfer flag (TCF) will reset automatically and FIFO is flushed + // if a transaction has been aborted. } void QSPI::waitBusy() @@ -156,10 +156,18 @@ void QSPI::waitTransfer() // constructor class qspi_flash qspi_flash::qspi_flash() { ; } +bool qspi_flash::test() +{ + // init qspi peripheral and check the device ID of the flash + + QSPI::init(); + return readID() == DEVICE_ID ? true : false; +} + uint8_t qspi_flash::read_status_reg() { - // status register can be reaa at any time and during every kind of + // status register can be read at any time and during every kind of // operation. indirect read mode, la comunicazione comincia dopo aver // scritto l'istruzione nel CCR register. 1 invio Read status register // command 2 ricevo un byte di dati con il valore dello status register. @@ -245,22 +253,32 @@ uint32_t qspi_flash::readID() // Expect to receive 3 bytes regarding ID of the flash QUADSPI->DLR = 2; - // DEVE ESSERE FATTO PRIMA DI SCRIVERE L'ISTRUZIONE NEL REGISTRO, - // PERCHè IN QUESTO CASO LA COMUNICAZIONE COMINCIA SCIVENDO L'ISTRUZIONE IN - // CCR QSPI::enable(); - // Trigger communication start by writing the instruction + // Trigger communication by writing the instruction into CCR register QUADSPI->CCR |= Commands::READ_ID << QUADSPI_CCR_INSTRUCTION_Pos; // wait till communication is ended QSPI::waitTransfer(); + // sus: even if some bytes have been received, the FIFO need some time to + // store them. + Thread::sleep(1); + // if there are some bytes in the quadspi buffer (FIFO), read them - if (QUADSPI->SR & (63 << QUADSPI_SR_FLEVEL_Pos)) + if ((QUADSPI->SR & QUADSPI_SR_FLEVEL) >> 8) { uint32_t myID = QUADSPI->DR; + QSPI::disable(); + + // the ID bytes order must be inverted + uint8_t lb = myID & (255U); // lowest byte + uint8_t mb = (myID >> 8) & (255U); // middle byte + uint8_t hb = (myID >> 16) & (255U); // highest byte + + myID = (lb << 16) | (mb << 8) | (hb); + return myID; } else @@ -322,7 +340,7 @@ void qspi_flash::waitProgress() while (isInProgress()) { - Thread::sleep(2); + Thread::sleep(1); } } @@ -338,6 +356,10 @@ uint8_t qspi_flash::read_byte(uint32_t address) // in this case, since no data is needed, the communication starts whenever // the adress register (QUADSPI->DR) is updated. + // check on correct address range + if (address > FlashMemory::MEMORY_SIZE) + return 0; + QSPI::abort_reset(); QUADSPI->CCR |= 1 << QUADSPI_CCR_FMODE_Pos | // Indirect read mode @@ -420,6 +442,10 @@ bool qspi_flash::sector_erase(uint32_t address) // 5 write_disable command to be sure // 6 check the result (flasg E_FAIL) + // check on address range + if ((address < 0) || (address > FlashMemory::MEMORY_SIZE)) + return false; + waitProgress(); write_enable(); @@ -462,6 +488,10 @@ bool qspi_flash::block32_erase(uint32_t address) // 5 write_disable command to be sure // 6 check the result (flasg E_FAIL) + // check on correct address range + if ((address < 0) || (address > FlashMemory::MEMORY_SIZE)) + return false; + waitProgress(); write_enable(); @@ -504,6 +534,10 @@ bool qspi_flash::block64_erase(uint32_t address) // 5 write_disable command, just to be sure // 6 check the result (flasg E_FAIL) + // check on correct address range + if ((address < 0) || (address > FlashMemory::MEMORY_SIZE)) + return false; + waitProgress(); write_enable(); @@ -535,9 +569,11 @@ bool qspi_flash::block64_erase(uint32_t address) return check_erase(); } -bool qspi_flash::byte_program(uint8_t data, uint32_t address) +bool qspi_flash::byte_program(uint8_t data, uint32_t address, bool verify) { + // double-check data may take some extra time ! + // write a byte at the specified address (any address is ok) // 1 wait till every memory operation is ended // 2 write enable @@ -546,6 +582,10 @@ bool qspi_flash::byte_program(uint8_t data, uint32_t address) // 5 write disable // 6 return the result + // check on address range + if ((address < 0) || (address > FlashMemory::MEMORY_SIZE)) + return false; + waitProgress(); write_enable(); @@ -575,6 +615,13 @@ bool qspi_flash::byte_program(uint8_t data, uint32_t address) write_disable(); + // if verify = true, double check on byte program operation + if (verify == true) + { + if (read_byte(address) != data) + return false; + } + return check_program(); } @@ -603,7 +650,10 @@ uint8_t qspi_flash::read_security_reg() // wait till data trasfer is complete QSPI::waitTransfer(); - uint8_t value = (uint8_t)QUADSPI->DR; + // sus, ma funziona, stesso problema nella readID() + Thread::sleep(1); + + uint32_t value = (uint8_t)QUADSPI->DR; QSPI::disable(); @@ -663,11 +713,11 @@ void qspi_flash::software_reset() bool qspi_flash::check_erase() { - // check for bit E_FAIL in security register of memory: - // E_fail = 1 the last erase operation has failed - // e_fail = 0 tha last operation has succeded - // returns true - erase operation has succeded - // returns false - erase operation has failed + // ATTTENTION! - this function check only if the last erase operation has + // been completed, so it's not so reliable ! check for bit E_FAIL in + // security register of memory: E_fail = 1 the last erase operation has + // failed e_fail = 0 tha last operation has succeded returns true - erase + // operation has succeded returns false - erase operation has failed uint8_t reg = read_security_reg(); return reg & (1 << 6) ? false : true; @@ -676,10 +726,225 @@ bool qspi_flash::check_erase() bool qspi_flash::check_program() { - // check for bit P_FAIL in security register of memory: - // returns true - erase operation has succeded - // returns false - erase operation has failed + // ATTTENTION! - this function check only if the last operation has been + // completed, so it's not so reliable ! check for bit P_FAIL in security + // register of memory: returns true - erase operation has succeded returns + // false - erase operation has failed uint8_t reg = read_security_reg(); return reg & (1 << 5) ? false : true; } + +bool qspi_flash::read_sector(std::vector<uint8_t>& vector, uint32_t sector_num) +{ + + // read an entire sector of the flash into a vector + // that will modify the vector and his elements. + // that fix size and capacity of the vector to SECTOR_SIZE. + + if (sector_num < 0 || sector_num > SECTORS_NUM) + { + return false; + } + + // reserve enough bytes to retain a sector of the flash, also + // make sure that size parameter match with the capacity. + if (vector.capacity() < SECTOR_SIZE) + { + vector.reserve(SECTOR_SIZE); + vector.resize(vector.capacity()); // SUS, altrimenti size != capacity + } + + if (vector.capacity() >= SECTOR_SIZE) + { + vector.resize(SECTOR_SIZE); + vector.shrink_to_fit(); + } + + uint32_t addr = SECTOR_SIZE * sector_num; + + uint32_t index = 0; + for (index = 0; index < vector.capacity(); index++) + { + vector[index] = read_byte(addr); + addr++; + } + + return true; +} + +bool qspi_flash::page_program(std::vector<uint8_t>& vector, + uint32_t start_address, bool verify) +{ + + // fifo interna: 32 bytes + // imposta prima il dlr + // scrivi byte per byte nel DR + // program the last 256 bytes of a vector starting by a specific page + // address. WEL bit is set to zero automatically after the program + // operation. NO WRITE_DISABLE the address specified must be a starting + // address of a page !!!! + + // not a starting address of a page + if ((start_address % PAGE_SIZE) != 0) + return false; + + // start_address out of address space of the memory + if (start_address >= MEMORY_SIZE) + return false; + + // empty vector + if (vector.size() == 0) + return false; + + // vector bigger than a page size + if (vector.size() > PAGE_SIZE) + return false; + + write_enable(); + + QSPI::abort_reset(); + + // idirect write mode + QUADSPI->CCR |= QUADSPI_CCR_DMODE_0 | // data on a single line + QUADSPI_CCR_ADSIZE_1 | // address size 24 bit + QUADSPI_CCR_ADMODE_0 | // address on a single line + QUADSPI_CCR_IMODE_0; // instruction on a single line + + QSPI::enable(); + + // page program command + QUADSPI->CCR |= Commands::PAGE_PROGRAM; + + // number of bytes to be transferred + QUADSPI->DLR = vector.size() - 1; + + // starting address + QUADSPI->AR = start_address; + + // load data vector into the QUADSPI FIFO + uint16_t i = 0; + for (i = 0; i < vector.size(); i++) + { + + // if FIFO is full - wait till it has at least a byte available. + while (((QUADSPI->SR & QUADSPI_SR_FLEVEL) >> 8) >= 32) + { + ; + } + + // add a single byte to be sent into the QSPI FIFO + ((uint8_t*)&QUADSPI->DR)[0] = static_cast<uint8_t>(vector[i]); + } + + QSPI::waitBusy(); + + waitProgress(); + + // if verify flag is set, double check on written data + if (verify == true) + { + for (i = 0; i < vector.size(); i++) + { + + if (read_byte(start_address + i) != vector[i]) + return false; + } + } + + return check_program(); +} + +bool qspi_flash::write_vector(std::vector<uint8_t>& vector, uint32_t sector_num, + bool verify_write) +{ + + // this function program into the flash just the real elements of the vector + // (size). THE VECTOR PASSED MUST HAVE SAME SIZE AND CAPACITY. return true: + // program operation succeded return false: program operation failed + + // wrong secton_num specified + if (sector_num < 0 || sector_num >= SECTORS_NUM) + { + return false; + } + + // if the vector doesn't have elements + if (vector.size() == 0 || vector.capacity() == 0) + { + return false; + } + + // if the vector is bigger than the flash capacity + if (vector.size() > MEMORY_SIZE) + return false; + + // if the whole vector is bigger than the rest of sectors starting by + // sector_num + if (vector.size() > (SECTOR_SIZE * (SECTORS_NUM - sector_num))) + return false; + + // constant start address + uint32_t const start_address = SECTOR_SIZE * sector_num; + + // compute number of sectors needed to store the vector, then add one more + // partial sector for the last part of vector. + uint32_t sectors_needed = vector.size() / SECTOR_SIZE; + if ((vector.size() % SECTOR_SIZE) != 0) + sectors_needed += 1; + + // erase all sectors needed to store the entire vector + uint32_t sector_index = 0; + for (sector_index = 0; sector_index < sectors_needed; sector_index++) + { + if (sector_erase(SECTOR_SIZE * (sector_num + sector_index)) == false) + return false; + } + + // compute the number of pages needed to store the entire vector + uint32_t pages_needed = vector.size() / PAGE_SIZE; + if ((vector.size() % PAGE_SIZE) != 0) + pages_needed += 1; + + // creating a copy vector + std::vector<uint8_t> v; + v.reserve(PAGE_SIZE); + v.resize(0); + + // for every page needed + uint32_t page = 0; + uint32_t elem = 0; + for (page = 0; page < pages_needed; page++) + { + v.resize(0); + uint32_t start_elem = page * PAGE_SIZE; + for (elem = start_elem; + (elem < start_elem + PAGE_SIZE) && (elem < vector.size()); elem++) + { + v.push_back(vector[elem]); + } + + if (page_program(v, start_address + (page * PAGE_SIZE), false) == false) + return false; + } + + // if verify_write is true: + // check that the bytes written into the flash match with the ones in the + // vector. + if (verify_write) + { + + uint32_t index = 0; + uint32_t addr = start_address; + for (index = 0; index < vector.size(); index++) + { + if (read_byte(addr) != vector[index]) + { + return false; + } + addr++; + } + } + + return true; +} \ No newline at end of file diff --git a/src/tests/drivers/QuadSpi-Flash/qspi-flash.h b/src/tests/drivers/QuadSpi-Flash/qspi-flash.h index d4fd7c4e84e341379e5305a456c25edaec6187e4..fc93f79f44ad2ed53252c078d57b62b1b532425b 100644 --- a/src/tests/drivers/QuadSpi-Flash/qspi-flash.h +++ b/src/tests/drivers/QuadSpi-Flash/qspi-flash.h @@ -27,9 +27,9 @@ using namespace miosix; using namespace Boardcore; -/* driver for MX25R3235FM1IL0 flash memory chip - * model of flash memory on compute unit: MX25R3235FM1IL0 4MB - * FLASH memory space organisation: +/* driver for MX25R3235FM1IL0 flash memory chip + * model of flash memory on compute unit: MX25R3235FM1IL0 4MB, device ID: + * 0xC22816 FLASH memory space organisation: * - number of byte in the memory: 4.194.304 >> about 4 MB * - "pages" of 256 Byte each - number of pages: 16.384 * - "sector" of about 4 KByte - number of sector: 1.024 @@ -40,6 +40,9 @@ using namespace Boardcore; namespace FlashMemory { +// device id of the flash +static const uint32_t DEVICE_ID = 0xC22816; + static const uint32_t PAGES_PER_SECTOR = 16; static const uint32_t SECTORS_PER_BLOCK32 = 8; @@ -71,7 +74,7 @@ void disable(); // init peripheral clock and GPIO void init(); -// abort any operation and reset configuration register (CCR) +// abort any ongoing operation and reset configuration register (CCR) void abort_reset(); // wait till the current operation is ended @@ -95,7 +98,21 @@ public: // read unique device ID uint32_t readID(); - // erase the entire memory chip - THIS OPERATION MIGHT TAKE A WHILE!! + // test the communication with the device by checking on its ID + bool test(); + + // write a vector into a sector of the flash + bool write_vector(std::vector<uint8_t>& vector, uint32_t sector_num, + bool verify_write); + + // read an std::vector starting by a specific sectro number + bool read_sector(std::vector<uint8_t>& vector, uint32_t sector_num); + + // program a page into the flash memory + bool page_program(std::vector<uint8_t>& vector, uint32_t start_address, + bool verify); + + // erase the entire memory chip - THIS OPERATION WILL TAKE A WHILE!! bool chip_erase(); // erase the sector which contains the address (24 bit) specified @@ -110,11 +127,11 @@ public: // read a byte at a specific address (24 bit) in memory uint8_t read_byte(uint32_t address); - // write a byte at a specific address (24 bit) in memory - bool byte_program(uint8_t data, uint32_t address); + // program a byte at a specific address (24 bit) in memory + bool byte_program(uint8_t data, uint32_t address, bool verify); // ATTENTION it may take a while! - makes the flash return to power-on - // default status. + // default state void software_reset(); // check last erase operation result @@ -123,13 +140,19 @@ public: // check last program operation result bool check_program(); -private: // enable writing void write_enable(); + // read status register of the flash memory + uint8_t read_status_reg(); + // disable writing void write_disable(); + // read security register of the flash + uint8_t read_security_reg(); + +private: // wait till flash has executed the current operation void waitProgress(); @@ -137,11 +160,8 @@ private: // registers) bool isInProgress(); - // read security register of the flash - uint8_t read_security_reg(); - - // read status register of the flash memory - uint8_t read_status_reg(); + // true = quadspi initialised - false = not initialised yet + bool initialised = false; // most important flash memory commands enum Commands @@ -149,7 +169,7 @@ private: // read unique ID of the memory READ_ID = 0x9F, - // write enable, needs to be executed before modify any data + // write enable, needs to be executed before writing any data WRITE_ENABLE = 0x06, // write disable @@ -161,13 +181,13 @@ private: // write status register WRITE_STATUS_REG = 0x01, - // read secutity register + // read security register READ_SECURITY_REG = 0x2B, // read configuration register READ_CONFIG_REGISTER = 0x15, - // read data from memory + // read data bytes from memory READ = 0x03, // write a page on memory. @@ -176,10 +196,10 @@ private: // erase a specific sector of the memory SECTOR_ERASE = 0x20, - // erase a specific block of 32KB of the memory + // erase a specific block of 32KB on the memory BLOCK_32_ERASE = 0x52, - // erase a specific block of 64KB of the memory + // erase a specific block of 64KB on the memory BLOCK_64_ERASE = 0xD8, // erase all data on the chip - THIS COULD TAKE A LONG TIME ! diff --git a/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp b/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp index fea1e37ab658172330cae8a70b2341984a6530ff..46ee84fd2bd3d8800b0460329aa4ff57d58f04cb 100644 --- a/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp +++ b/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp @@ -26,107 +26,91 @@ qspi_flash mymemory; int main() { - // test readID() FUNZIONAAAA - printf("starting ID test!\n"); - mymemory.init(); - uint32_t ID = mymemory.readID(); - - printf("ID: %x\n", ID); - - printf("end ID test\n"); + std::vector<uint8_t> v; + v.reserve(20000); + for (uint32_t i = 0; i < v.capacity(); i++) + v.push_back(5); + v.resize(v.capacity()); - // test write enable command FUNZIONAAAAAAA /* - printf("start write_enable command\n"); - - mymemory.write_enable(); - - printf("----- end write_enable command\n"); + printf("vettore: \n"); + uint32_t i = 0; + for (i = 0; i < v.size(); i++) + { + printf("v[%d]: %d \n", i, v[i]); + } + printf("vector size: %u\n", v.size()); + printf("vector capacity: %d\n", v.capacity()); */ - // test write disable command FUNZIONAAAAAAA - /* - printf("start write_disable command\n"); - - mymemory.write_disable(); + // printf("result: %d\n", mymemory.write_vector(v, 1019, true)); - printf("----- end write_disable command\n"); - */ + // --------- read FUNZIONA ------------- + std::vector<uint8_t> v2; + mymemory.read_sector(v2, 1023); + printf("\nvettore v2: \n"); + uint32_t a = 0; + for (a = 0; a < FlashMemory::SECTOR_SIZE; a++) + { + printf("v2[%d]: %d \n", a, v2[a]); + } + printf("v2 size: %d\n", v2.size()); + printf("v2 capacity: %d\n", v2.capacity()); - // test funzione isInProgress - /* - printf("test funzione isInProgress()\n"); - - printf("valore isInProgress(): %d\n", mymemory.isInProgress()); - - printf("----- end isinProgress test\n"); - - // test read security_reg() - printf("\nvalore security register: %d\n", mymemory.read_security_reg()); - */ + // ------------- ATTENZIONE SU FUNZIONI DI LETTURA ----------------- + // numero di bytes della flash = 2 ^ (FSIZE + 1) + // impostare la corretta dimensione della flash è necessario al corretto + // funzionamento delle operazioni di lettura dalla flash. tutte le + // operazioni di lettura della memoria a partire da un indirizzo che non può + // essere contenuto nella memoria di dimensione indicata (FSIZE) non vengono + // eseguite dalla periferica QUADSPI. esempio: se la dimensione impostata è + // di 4 byte allora gli indirizzi accettati sono: 0-3b. - // test funzione sector erase SEMBRA FUNZIONARE FINO AD ORA !!!! - /* - printf("\nstart TEST sector_erase()\n"); + // - read_sector funziona bene. - printf("valore ritornato: %d\n", mymemory.sector_erase(0)); + // - program_sector funzionano bene con verify_write - printf("end test sector_erase()\n"); - */ + // - page_program funziona beneeeeee - // test funzione byte_program() - printf("\ntest funzione byte_program()\n"); + // - readID() funziona bene con sleep(1ms) - printf("valore ritornato: %d\n", mymemory.byte_program(55U, 0)); + // - test() funziona bene - printf("end test byte_program()\n"); + // - studiare come aggiungere quadspi mode: non vale la pena ad oggi - // test funzione read_byte(): OCCHIO IMPOSTA SEMPRE LA DIMENSIONE DELLA - // FLASH - printf("\ntest funzione read_byte()\n"); + // - waitProgress più veloce: funziona tutto ok - // test block32_erase(): FUNZIONA - printf("valore block32_erase(): %d\n", mymemory.block32_erase(0x3FFFFF)); + // ----------- TEST ------ lettura security register + // ho modificato byte_program e read_security_reg() + // senza sleep() non ci sono dati nella FIFO. con sleep arriva sempre il + // byte data. read_security_reg() sembra leggere il registro, da provare con + // suspend commands. se non va, check con rilettura dei dati. - // test block64_erase(): FUNZIONA - printf("valore block64_erase(): %d\n", mymemory.block64_erase(0x3fffff)); + // assumo che la lettura del security_register sia corretta, verifico la + // riuscita delle operazioni più importanti rileggendo i dati. - printf("valore read_byte: %d\n", mymemory.read_byte(0)); + // su funzioni meno importanti controllare check_operation() e controllare + // bene gli argomenti siano corretti. Nelle altre controllo con verify. - printf("----- end read_byte() test\n"); + // modifico byte_program con flag verify e controllo su argomenti: FUNZIONA + // testata - // test funzione reset(): FUNZIONA - /* - printf("\n------- start test funzione reset() ----------\n"); + // modifico tutte le erase: FUNZIONANNO testate - Thread::sleep(100); - mymemory.write_enable(); - printf("status reg prima : %d\n", mymemory.read_status_reg()); - //mymemory.software_reset(); - printf("status reg dopo: %d\n", mymemory.read_status_reg()); + // modifico read_byte: FUNZIONA testata - printf("------- end test funzione reset() ----------\n"); - */ + // page_program modificata: aggiunto verify flag FUNZIONA testata. - // test erase chip function(): FUNZIONA - /* - printf("\nstart TEST erase chip function\n"); + // test finali page_program, read_sector, e program_sector FUNZIONANO + // TESTATE. - printf("valore ritornato: %d\n", mymemory.chip_erase()); + // METTERE FLAG INITIALISED - printf("end of the erase chip operation.\n "); - */ + // - commentare meglio e sistemare funzioni public e private. - // ------------- ATTENZIONE SU FUNZIONI DI LETTURA ----------------- - // numero di bytes della flash = 2 ^ (FSIZE + 1) - // impostare la corretta dimensione della flash è necessario al corretto - // funzionamento delle operazioni di lettura dalla flash. tutte le - // operazioni di lettura della memoria a partire da un indirizzo che non può - // essere contenuto nella memoria di dimensione indicata (FSIZE) non vengono - // eseguite dalla periferica QUADSPI. esempio: se la dimensione impostata è - // di 4 byte allora gli indirizzi accettati sono: 0-3b + // - forse aggiungere controllo anti loop operation. while (true) Thread::sleep(1000);