From 13791dba570fb23ab328dd7b495087ea3419e8fa Mon Sep 17 00:00:00 2001 From: Valerio Flamminii <valerio.flamminii@skywarder.eu> Date: Sat, 9 Mar 2024 07:34:45 +0100 Subject: [PATCH] test di commit --- .../drivers/QuadSpi-Flash/qspi-flash.cpp | 723 +++++++++--------- src/tests/drivers/QuadSpi-Flash/qspi-flash.h | 179 +++-- .../drivers/QuadSpi-Flash/test-Qflash.cpp | 128 ++-- 3 files changed, 543 insertions(+), 487 deletions(-) diff --git a/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp b/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp index fd4b42bfa..4ff2a5ced 100644 --- a/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp +++ b/src/tests/drivers/QuadSpi-Flash/qspi-flash.cpp @@ -1,10 +1,30 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Valerio Flamminii + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "qspi-flash.h" using namespace miosix; using namespace Boardcore; using namespace FlashMemory; - /** * QSPI Flash pins * @@ -23,14 +43,12 @@ GpioPin flash_io1(GPIOF_BASE, 9); GpioPin flash_io2(GPIOF_BASE, 7); GpioPin flash_io3(GPIOF_BASE, 6); - void QSPI::enable() { QUADSPI->CR |= QUADSPI_CR_EN; } - void QSPI::disable() { QUADSPI->CR &= ~QUADSPI_CR_EN; } - -void QSPI::init() { +void QSPI::init() +{ // init GPIO peripheral pins flash_ncs.mode(Mode::ALTERNATE); @@ -52,613 +70,616 @@ void QSPI::init() { flash_io3.alternateFunction(9); flash_io3.speed(Speed::_100MHz); - // init peripheral clock + // init peripheral clock ClockUtils::enablePeripheralClock((QUADSPI_TypeDef*)QSPI_BASE); RCC_SYNC(); - Thread::sleep(200); + Thread::sleep(200); - // abort possible ongoing command + // abort possible ongoing command QUADSPI->CR |= QUADSPI_CR_ABORT; - + // Wait while aborted - while (QUADSPI->CR & QUADSPI_CR_ABORT) {;} - - // disable peripheral - QSPI::disable(); + while (QUADSPI->CR & QUADSPI_CR_ABORT) + { + ; + } - // reset configuration registers + // disable peripheral + QSPI::disable(); + + // reset configuration registers QUADSPI->CR = 0; QUADSPI->DCR = 0; QUADSPI->CCR = 0; QUADSPI->DLR = 0; - + // reset transfer complete flag (TCF) - QUADSPI->FCR &= ~(1 << QUADSPI_FCR_CTCF_Pos); + QUADSPI->FCR &= ~(1 << QUADSPI_FCR_CTCF_Pos); // peripheral default initialization - QUADSPI->CR |= QUADSPI_CR_SSHIFT | // Wait a full cycle to read + QUADSPI->CR |= + QUADSPI_CR_SSHIFT | // Wait a full cycle to read 3 << QUADSPI_CR_PRESCALER_Pos; // QSPI clock = 216MHz / 4 = 54MHz - + // -------------- must be setted for read function ---------------------- - // impostare la dimensione della memoria è necessario alle operazioni di lettura della flash - QUADSPI->DCR |= 21 << QUADSPI_DCR_FSIZE_Pos; // Flash size 32Mb = 4MB = 2^(21+1) bytes + // impostare la dimensione della memoria è necessario alle operazioni di + // lettura della flash + QUADSPI->DCR |= + 21 << QUADSPI_DCR_FSIZE_Pos; // Flash size 32Mb = 4MB = 2^(21+1) bytes } +void QSPI::abort_reset() +{ -void QSPI::abort_reset() { - - // abort possible ongoing command + // abort possible ongoing command QUADSPI->CR |= QUADSPI_CR_ABORT; - + // Wait while aborted - while (QUADSPI->CR & QUADSPI_CR_ABORT) {;} + while (QUADSPI->CR & QUADSPI_CR_ABORT) + { + ; + } + + // to be sure that the peripheral is disabled + QSPI::disable(); - // to be sure that the peripheral is disabled - QSPI::disable(); - // reset configuration register QUADSPI->CCR = 0; - // transfer flag (TCF) will reset automatically if a transaction has been aborted. + // transfer flag (TCF) will reset automatically if a transaction has been + // aborted. } - -void QSPI::waitBusy() { - while(QUADSPI->SR & (1 << QUADSPI_SR_BUSY_Pos)) {;} +void QSPI::waitBusy() +{ + while (QUADSPI->SR & (1 << QUADSPI_SR_BUSY_Pos)) + { + ; + } } - -void QSPI::waitTransfer() { +void QSPI::waitTransfer() +{ // wait till the end of the communication - while (!(QUADSPI->SR & (1 << QUADSPI_SR_TCF_Pos))) {;} + while (!(QUADSPI->SR & (1 << QUADSPI_SR_TCF_Pos))) + { + ; + } // reset transfer complete flag (TCF) - QUADSPI->FCR &= ~(1 << QUADSPI_FCR_CTCF_Pos); - + QUADSPI->FCR &= ~(1 << QUADSPI_FCR_CTCF_Pos); } - // constructor class qspi_flash -qspi_flash::qspi_flash() {;} +qspi_flash::qspi_flash() { ; } +uint8_t qspi_flash::read_status_reg() +{ -uint8_t qspi_flash::read_status_reg() { - - // status register can be reaa 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. + // status register can be reaa 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. - QSPI::abort_reset(); + QSPI::abort_reset(); QUADSPI->CCR |= 1 << QUADSPI_CCR_FMODE_Pos | // Indirect read mode - 1 << QUADSPI_CCR_DMODE_Pos | // Data on 1-wire - 0 << QUADSPI_CCR_ABMODE_Pos | // No alternate bytes - 0 << QUADSPI_CCR_ADMODE_Pos | // No address - 1 << QUADSPI_CCR_IMODE_Pos; // Instruction on 1-wire - + 1 << QUADSPI_CCR_DMODE_Pos | // Data on 1-wire + 0 << QUADSPI_CCR_ABMODE_Pos | // No alternate bytes + 0 << QUADSPI_CCR_ADMODE_Pos | // No address + 1 << QUADSPI_CCR_IMODE_Pos; // Instruction on 1-wire + // Expect to receive 1 byte (flash status register) - QUADSPI->DLR = 0; + QUADSPI->DLR = 0; - // DEVE ESSERE FATTO PRIMA DI SCRIVERE L'ISTRUZIONE NEL REGISTRO, - // PERCHè IN QUESTO CASO LA COMUNICAZIONE COMINCIA SCIVENDO L'ISTRUZIONE IN CCR + // 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 - QUADSPI->CCR |= Commands::READ_STATUS_REG << QUADSPI_CCR_INSTRUCTION_Pos; + QUADSPI->CCR |= Commands::READ_STATUS_REG << QUADSPI_CCR_INSTRUCTION_Pos; // wait till data trasfer is complete QSPI::waitTransfer(); - - // dopo waitTranfer() mi aspetto ci sia solo un byte nella fifo, posso fare - // direttamente il cast a uint8_t (byte) - uint32_t value = (uint8_t) QUADSPI->DR; + + // dopo waitTranfer() mi aspetto ci sia solo un byte nella fifo, posso fare + // direttamente il cast a uint8_t (byte) + uint32_t value = (uint8_t)QUADSPI->DR; // disable peripheral - QSPI::disable(); + QSPI::disable(); - return value; + return value; } +void qspi_flash::write_enable() +{ -void qspi_flash::write_enable() { - - // in indirect write mode with no data or address phase (DMODE = 0, ADMODE = 0) the - // communication starts whenever the CCR register is written. - // 1 send wren command - // 2 read status register - // 3 wait for bit WEL = 1 - // poi program/erase commands - - QSPI::abort_reset(); + // in indirect write mode with no data or address phase (DMODE = 0, ADMODE = + // 0) the communication starts whenever the CCR register is written. 1 send + // wren command 2 read status register 3 wait for bit WEL = 1 poi + // program/erase commands - // indirect write mode, istruction on 1 wire, no data, no address, no alternate bytes - QUADSPI->CCR |= 1 << QUADSPI_CCR_IMODE_Pos; + QSPI::abort_reset(); + + // indirect write mode, istruction on 1 wire, no data, no address, no + // alternate bytes + QUADSPI->CCR |= 1 << QUADSPI_CCR_IMODE_Pos; - QSPI::enable(); + QSPI::enable(); // start communication writing the instruction to CCR register busy bit = 1 - QUADSPI->CCR |= Commands::WRITE_ENABLE; + QUADSPI->CCR |= Commands::WRITE_ENABLE; - QSPI::waitBusy(); + QSPI::waitBusy(); QSPI::disable(); - - // check status register until bit WEL = 1 - uint8_t status = read_status_reg(); - - while(!(status & (1 << 1))) { // WEL_pos = 1 è il secondo bit - Thread::sleep(1); - status = read_status_reg(); - } - -} + // check status register until bit WEL = 1 + uint8_t status = read_status_reg(); -bool qspi_flash::init() { - - QSPI::init(); - - return true; + while (!(status & (1 << 1))) + { // WEL_pos = 1 è il secondo bit + Thread::sleep(1); + status = read_status_reg(); + } } +void qspi_flash::init() { QSPI::init(); } +uint32_t qspi_flash::readID() +{ -uint32_t qspi_flash::readID() { - - QSPI::abort_reset(); + QSPI::abort_reset(); QUADSPI->CCR |= 1 << QUADSPI_CCR_FMODE_Pos | // Indirect read mode - 1 << QUADSPI_CCR_DMODE_Pos | // Data on 1-wire - 0 << QUADSPI_CCR_ABMODE_Pos | // No alternate bytes - 0 << QUADSPI_CCR_ADMODE_Pos | // No address - 1 << QUADSPI_CCR_IMODE_Pos; // Instruction on 1-wire - + 1 << QUADSPI_CCR_DMODE_Pos | // Data on 1-wire + 0 << QUADSPI_CCR_ABMODE_Pos | // No alternate bytes + 0 << QUADSPI_CCR_ADMODE_Pos | // No address + 1 << QUADSPI_CCR_IMODE_Pos; // Instruction on 1-wire + // Expect to receive 3 bytes regarding ID of the flash - QUADSPI->DLR = 2; + 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 + // 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 - QUADSPI->CCR |= Commands::READ_ID << QUADSPI_CCR_INSTRUCTION_Pos; + QUADSPI->CCR |= Commands::READ_ID << QUADSPI_CCR_INSTRUCTION_Pos; // wait till communication is ended - QSPI::waitTransfer(); + QSPI::waitTransfer(); // if there are some bytes in the quadspi buffer (FIFO), read them - if (QUADSPI->SR & (63 << QUADSPI_SR_FLEVEL_Pos)) { - uint32_t myID = QUADSPI->DR; + if (QUADSPI->SR & (63 << QUADSPI_SR_FLEVEL_Pos)) + { + uint32_t myID = QUADSPI->DR; QSPI::disable(); return myID; } - else { + else + { QSPI::disable(); - return 0; + return 0; } } +void qspi_flash::write_disable() +{ -void qspi_flash::write_disable() { - - // in indirect write mode with no data or address phase (DMODE = 0, ADMODE = 0) the - // communication starts whenever the CCR register is written. - // 1 send wrid command (0x4) - // 2 read status register - // 3 wait for bit WEL = 0 - // poi return - - QSPI::abort_reset(); + // in indirect write mode with no data or address phase (DMODE = 0, ADMODE = + // 0) the communication starts whenever the CCR register is written. 1 send + // wrid command (0x4) 2 read status register 3 wait for bit WEL = 0 poi + // return - // indirect write mode, istruction on 1 wire, no data, no address, no alternate bytes - QUADSPI->CCR |= 1 << QUADSPI_CCR_IMODE_Pos; + QSPI::abort_reset(); - QSPI::enable(); + // indirect write mode, istruction on 1 wire, no data, no address, no + // alternate bytes + QUADSPI->CCR |= 1 << QUADSPI_CCR_IMODE_Pos; + + QSPI::enable(); // start communication writing the instruction to CCR register busy bit = 1 - QUADSPI->CCR |= Commands::WRITE_DISABLE; + QUADSPI->CCR |= Commands::WRITE_DISABLE; - QSPI::waitBusy(); + QSPI::waitBusy(); QSPI::disable(); - - // check status register until bit WEL = 0 - uint8_t status = read_status_reg(); - while(status & (1 << 1)) { // WEL è il secondo bit - Thread::sleep(1); - status = read_status_reg(); - } + // check status register until bit WEL = 0 + uint8_t status = read_status_reg(); + while (status & (1 << 1)) + { // WEL è il secondo bit + Thread::sleep(1); + status = read_status_reg(); + } } +bool qspi_flash::isInProgress() +{ -bool qspi_flash::isInProgress() { - - // check if the memory is executing some operation. - // bit WIP in flash status register is set if a program/erase/write to - // registers is being executed. + // check if the memory is executing some operation. + // bit WIP in flash status register is set if a program/erase/write to + // registers is being executed. // 1 read flash status register - // 2 bit WIP = 1: operation in progress / WIP = 0 no one operation in progress. + // 2 bit WIP = 1: operation in progress / WIP = 0 no one operation in + // progress. - uint8_t status_reg = read_status_reg(); - return (status_reg & 1) ? true : false; + uint8_t status_reg = read_status_reg(); + return (status_reg & 1) ? true : false; } +void qspi_flash::waitProgress() +{ -void qspi_flash::waitProgress() { - - while(isInProgress()) { - Thread::sleep(2); + while (isInProgress()) + { + Thread::sleep(2); } - } +uint8_t qspi_flash::read_byte(uint32_t address) +{ + // THE MEMORY SIZE NEED TO BE SETTED IN DCR REGISTER !!!!!!! -uint8_t qspi_flash::read_byte(uint32_t address) { - - // THE MEMORY SIZE NEED TO BE SETTED IN DCR REGISTER !!!!!!! - - // read one byte from the memory starting at a specific address. + // read one byte from the memory starting at a specific address. // 1 send READ command - // 2 send 3-byte address + // 2 send 3-byte address // 3 read only the first byte of data - // in this case, since no data is needed, the communication starts whenever the adress - // register (QUADSPI->DR) is updated. + // in this case, since no data is needed, the communication starts whenever + // the adress register (QUADSPI->DR) is updated. - QSPI::abort_reset(); + QSPI::abort_reset(); QUADSPI->CCR |= 1 << QUADSPI_CCR_FMODE_Pos | // Indirect read mode - QUADSPI_CCR_DMODE_0 | // data on a single line - QUADSPI_CCR_ADSIZE_1 | // 3-byte (24 bit) address - QUADSPI_CCR_ADMODE_0 | // address on a single line - QUADSPI_CCR_IMODE_0; // instruction on a single line - - // read istruction in CCR register - QUADSPI->CCR |= Commands::READ; - + QUADSPI_CCR_DMODE_0 | // data on a single line + QUADSPI_CCR_ADSIZE_1 | // 3-byte (24 bit) address + QUADSPI_CCR_ADMODE_0 | // address on a single line + QUADSPI_CCR_IMODE_0; // instruction on a single line + + // read istruction in CCR register + QUADSPI->CCR |= Commands::READ; + // just 1 byte of data is supposed to be transferred - QUADSPI->DLR = 0; + QUADSPI->DLR = 0; - QSPI::enable(); + QSPI::enable(); // start communication by specifing the address QUADSPI->AR = address; - QSPI::waitTransfer(); + QSPI::waitTransfer(); - uint8_t value = (uint8_t) QUADSPI->DR; + uint8_t value = (uint8_t)QUADSPI->DR; - QSPI::disable(); + QSPI::disable(); - return value; + return value; } +bool qspi_flash::chip_erase() +{ -bool qspi_flash::chip_erase() { - // erase the entire flash memory chip - // erase chip operation typical time: 30-60 s - // 1 wait until the memory has finished any operation in progress - // 2 write_enable command - // 3 erase chip command - // 4 wait till flash has completed the erase operation - // 5 write_disable command to be sure - // 6 read flag E_FAIL in security register to ckeck that the last - // erase operation has succeded. - // return: true = erase chip operation succeded, false = erase chip operation failed + // erase chip operation typical time: 30-60 s + // 1 wait until the memory has finished any operation in progress + // 2 write_enable command + // 3 erase chip command + // 4 wait till flash has completed the erase operation + // 5 write_disable command to be sure + // 6 read flag E_FAIL in security register to ckeck that the last + // erase operation has succeded. + // return: true = erase chip operation succeded, false = erase chip + // operation failed - waitProgress(); + waitProgress(); - write_enable(); - - QSPI::abort_reset(); + write_enable(); - // set quadspi CCR register: - // indirect write mode, no address, no data. all on one wire. - QUADSPI->CCR |= QUADSPI_CCR_IMODE_0; // istruction on one wire + QSPI::abort_reset(); - QSPI::enable(); + // set quadspi CCR register: + // indirect write mode, no address, no data. all on one wire. + QUADSPI->CCR |= QUADSPI_CCR_IMODE_0; // istruction on one wire - // write istruction and start the communication + QSPI::enable(); + + // write istruction and start the communication QUADSPI->CCR |= Commands::ERASE_CHIP; - QSPI::waitBusy(); + QSPI::waitBusy(); - QSPI::disable(); + QSPI::disable(); - // wait till end of erase operation - waitProgress(); + // wait till end of erase operation + waitProgress(); - write_disable(); + write_disable(); - // return the result of chip erase operation - return check_erase(); + // return the result of chip erase operation + return check_erase(); } +bool qspi_flash::sector_erase(uint32_t address) +{ -bool qspi_flash::sector_erase(uint32_t address) { - - // erase a specific sector (4 KB), any address of the sector is a valid address. - // 1 wait until the memory has finished any operation in progress - // 2 write_enable command - // 3 erase sector command + // erase a specific sector (4 KB), any address of the sector is a valid + // address. 1 wait until the memory has finished any operation in progress + // 2 write_enable command + // 3 erase sector command // 4 wait till flash has completed the operation - // 5 write_disable command to be sure + // 5 write_disable command to be sure // 6 check the result (flasg E_FAIL) - waitProgress(); + waitProgress(); - write_enable(); + write_enable(); - QSPI::abort_reset(); + QSPI::abort_reset(); - // set quadspi CCR register: - // indirect write mode, 3-byte address , no data. all on one wire. - QUADSPI->CCR |= QUADSPI_CCR_IMODE_0 | // istruction on one wire - QUADSPI_CCR_ADSIZE_1 | // 3-byte address - QUADSPI_CCR_ADMODE_0; // address on a single line + // set quadspi CCR register: + // indirect write mode, 3-byte address , no data. all on one wire. + QUADSPI->CCR |= QUADSPI_CCR_IMODE_0 | // istruction on one wire + QUADSPI_CCR_ADSIZE_1 | // 3-byte address + QUADSPI_CCR_ADMODE_0; // address on a single line - QSPI::enable(); + QSPI::enable(); - // add instruction - QUADSPI->CCR |= Commands::SECTOR_ERASE; + // add instruction + QUADSPI->CCR |= Commands::SECTOR_ERASE; // start communication by writing the address in QUADSPI->AR - QUADSPI->AR = address; + QUADSPI->AR = address; - QSPI::waitBusy(); + QSPI::waitBusy(); - QSPI::disable(); + QSPI::disable(); - waitProgress(); + waitProgress(); - write_disable(); + write_disable(); - return check_erase(); + return check_erase(); } +bool qspi_flash::block32_erase(uint32_t address) +{ -// erase block (32K) which contains the address (24 bit) specified -bool qspi_flash::block32_erase(uint32_t address) { - - // erase a 32K block of data, any address of the block is valid - // 1 wait until the memory has finished any operation in progress - // 2 write_enable command - // 3 erase block_32 command + // erase a 32K block of data, any address of the block is valid + // 1 wait until the memory has finished any operation in progress + // 2 write_enable command + // 3 erase block_32 command // 4 wait till flash has completed the operation - // 5 write_disable command to be sure + // 5 write_disable command to be sure // 6 check the result (flasg E_FAIL) - waitProgress(); + waitProgress(); - write_enable(); + write_enable(); - QSPI::abort_reset(); + QSPI::abort_reset(); - // set quadspi CCR register - // indirect write mode, 3-byte address, no data. all on one wire. - QUADSPI->CCR |= QUADSPI_CCR_IMODE_0 | // istruction on one wire - QUADSPI_CCR_ADSIZE_1 | // 3-byte address - QUADSPI_CCR_ADMODE_0; // address on a single line + // set quadspi CCR register + // indirect write mode, 3-byte address, no data. all on one wire. + QUADSPI->CCR |= QUADSPI_CCR_IMODE_0 | // istruction on one wire + QUADSPI_CCR_ADSIZE_1 | // 3-byte address + QUADSPI_CCR_ADMODE_0; // address on a single line - QSPI::enable(); + QSPI::enable(); - // add instruction - QUADSPI->CCR |= Commands::BLOCK_32_ERASE; + // add instruction + QUADSPI->CCR |= Commands::BLOCK_32_ERASE; // start communication by writing the address in QUADSPI->AR QUADSPI->AR = address; - QSPI::waitBusy(); + QSPI::waitBusy(); - QSPI::disable(); + QSPI::disable(); - waitProgress(); + waitProgress(); - write_disable(); + write_disable(); - return check_erase(); + return check_erase(); } +bool qspi_flash::block64_erase(uint32_t address) +{ -// erase a block (32K) which contains the address (24 bit) specified -bool qspi_flash::block64_erase(uint32_t address) { - - // erase a 64K block of data, any address of the block is valid - // 1 wait until the memory has finished any operation in progress - // 2 write_enable command - // 3 erase block_64 command + // erase a 64K block of data, any address of the block is valid + // 1 wait until the memory has finished any operation in progress + // 2 write_enable command + // 3 erase block_64 command // 4 wait till flash has completed the operation - // 5 write_disable command, just to be sure + // 5 write_disable command, just to be sure // 6 check the result (flasg E_FAIL) - waitProgress(); + waitProgress(); - write_enable(); + write_enable(); - QSPI::abort_reset(); + QSPI::abort_reset(); - // set quadspi CCR register - // indirect write mode, 3-byte address, no data. all on one wire. - QUADSPI->CCR |= QUADSPI_CCR_IMODE_0 | // istruction on one wire - QUADSPI_CCR_ADSIZE_1 | // 3-byte address - QUADSPI_CCR_ADMODE_0; // address on a single line + // set quadspi CCR register + // indirect write mode, 3-byte address, no data. all on one wire. + QUADSPI->CCR |= QUADSPI_CCR_IMODE_0 | // istruction on one wire + QUADSPI_CCR_ADSIZE_1 | // 3-byte address + QUADSPI_CCR_ADMODE_0; // address on a single line - QSPI::enable(); + QSPI::enable(); - // add instruction - QUADSPI->CCR |= Commands::BLOCK_64_ERASE; + // add instruction + QUADSPI->CCR |= Commands::BLOCK_64_ERASE; // start communication by writing the address in QUADSPI->AR QUADSPI->AR = address; - QSPI::waitBusy(); + QSPI::waitBusy(); - QSPI::disable(); + QSPI::disable(); - waitProgress(); + waitProgress(); - write_disable(); + write_disable(); 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) { - // write a byte at the specified address (any address is ok) - // 1 wait till every memory operation is ended + // 1 wait till every memory operation is ended // 2 write enable - // 3 page program command + // 3 page program command // 4 wait till the operation is ended - // 5 write disable - // 6 return the result + // 5 write disable + // 6 return the result - waitProgress(); + waitProgress(); - write_enable(); + write_enable(); - QSPI::abort_reset(); + 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 + 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(); + QSPI::enable(); - // page program command - QUADSPI->CCR |= Commands::PAGE_PROGRAM; - - // address - QUADSPI->AR = address; + // page program command + QUADSPI->CCR |= Commands::PAGE_PROGRAM; - // trigger the communication by writing into data register + // address + QUADSPI->AR = address; + + // trigger the communication by writing into data register QUADSPI->DR = data; - QSPI::waitBusy(); + QSPI::waitBusy(); - waitProgress(); + waitProgress(); - write_disable(); + write_disable(); - return check_program(); + return check_program(); } +uint8_t qspi_flash::read_security_reg() +{ -uint8_t qspi_flash::read_security_reg() { - - // security register can be at any time and during avery kind of operation. - // in indirect read mode: - // 1 send read security register command (1-byte instruction) - // 2 receive one byte of data contatining the value of the register. + // security register can be read at any time and during every kind of + // operation. in indirect read mode: 1 - send read security register command + // (1-byte instruction) 2 - receive one byte of data containing the value of + // the register. - QSPI::abort_reset(); + QSPI::abort_reset(); QUADSPI->CCR |= QUADSPI_CCR_FMODE_0 | // Indirect read mode - QUADSPI_CCR_DMODE_0 | // data on one wire - QUADSPI_CCR_IMODE_0; // instruction on one wire - - + QUADSPI_CCR_DMODE_0 | // data on one wire + QUADSPI_CCR_IMODE_0; // instruction on one wire + // Expect to receive 1 byte (flash security register value) - QUADSPI->DLR = 0; + QUADSPI->DLR = 0; QSPI::enable(); - + // start communication by writing the instruction - QUADSPI->CCR |= Commands::READ_SECURITY_REG; + QUADSPI->CCR |= Commands::READ_SECURITY_REG; // wait till data trasfer is complete QSPI::waitTransfer(); - uint8_t value = (uint8_t) QUADSPI->DR; + uint8_t value = (uint8_t)QUADSPI->DR; - QSPI::disable(); - - return value; -} + QSPI::disable(); + return value; +} -void qspi_flash::software_reset() { +void qspi_flash::software_reset() +{ - // if software reset is performed at the same time of another programe/erase operation, - // that current operation will not be executed correctly, and data could be lost. + // if software reset is performed at the same time of another program/erase + // operation, that current operation will not be executed correctly, and + // some data could be lost. - // this functionality combines two commands, RSTEN and RST, - // they need to be sent according to this order: + // this functionality combines two commands, RSTEN and RST, + // they need to be sent according to this order: // 1 - RSTEN instruction (reset enable) - // 2 - RST instruction (software reset) - // if any operation is executed before the RST instruction, the reset enable (RSTEN) is - // invalid. + // 2 - RST instruction (software reset) + // if any operation is executed before the RST instruction, the reset enable + // (RSTEN) is invalid. // commands sequence: RSTEN>>wait 1ms>>RST>>wait 1ms // -------------------- send RSTEN command ------------------------- - waitProgress(); + waitProgress(); QSPI::abort_reset(); // indirect write mode, no data, no address, instruction on a single line - QUADSPI->CCR |= QUADSPI_CCR_IMODE_0; + QUADSPI->CCR |= QUADSPI_CCR_IMODE_0; - QSPI::enable(); + QSPI::enable(); - // start the communication by writing the reset enable instruction + // start the communication by writing the reset enable instruction QUADSPI->CCR |= Commands::RESET_ENABLE; - QSPI::waitBusy(); + QSPI::waitBusy(); - QSPI::disable(); + QSPI::disable(); - Thread::sleep(1); // wait 1 ms + Thread::sleep(1); // wait 1 ms // ------------------- send RST command -------------------------- - QSPI::abort_reset(); - - QUADSPI->CCR |= QUADSPI_CCR_IMODE_0; - - QSPI::enable(); - + QSPI::abort_reset(); + + QUADSPI->CCR |= QUADSPI_CCR_IMODE_0; + + QSPI::enable(); + QUADSPI->CCR |= Commands::RESET_MEMORY; - - QSPI::waitBusy(); - QSPI::disable(); + QSPI::waitBusy(); - Thread::sleep(1); -} + QSPI::disable(); + Thread::sleep(1); +} +bool qspi_flash::check_erase() +{ -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 = 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; + // returns true - erase operation has succeded + // returns false - erase operation has failed + uint8_t reg = read_security_reg(); + return reg & (1 << 6) ? false : true; } +bool qspi_flash::check_program() +{ - -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 + // returns true - erase operation has succeded + // returns false - erase operation has failed - uint8_t reg = read_security_reg(); + uint8_t reg = read_security_reg(); return reg & (1 << 5) ? false : true; - } diff --git a/src/tests/drivers/QuadSpi-Flash/qspi-flash.h b/src/tests/drivers/QuadSpi-Flash/qspi-flash.h index 96f701a38..d4fd7c4e8 100644 --- a/src/tests/drivers/QuadSpi-Flash/qspi-flash.h +++ b/src/tests/drivers/QuadSpi-Flash/qspi-flash.h @@ -1,3 +1,24 @@ +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Valerio Flamminii + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include <miosix.h> #include <utils/ClockUtils.h> @@ -6,17 +27,18 @@ using namespace miosix; using namespace Boardcore; - -/* model of flash memory on compute unit: MX25R3235FM1IL0 4MB +/* driver for MX25R3235FM1IL0 flash memory chip + * model of flash memory on compute unit: MX25R3235FM1IL0 4MB * 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 * - "block32" of about 32 KByte - number of block32: 128 * - "block64" of about 64 KByte - number of block64: 64 -*/ + */ -namespace FlashMemory { +namespace FlashMemory +{ static const uint32_t PAGES_PER_SECTOR = 16; static const uint32_t SECTORS_PER_BLOCK32 = 8; @@ -36,129 +58,129 @@ static const uint32_t BLOCK64_SIZE = BLOCK32_SIZE * 2; // memory size in byte static const uint32_t MEMORY_SIZE = BLOCK64_SIZE * BLOCK64_NUM; // about 4 MB -}; - +}; // namespace FlashMemory // QUADSPI peripheral utility-stuff -namespace QSPI { +namespace QSPI +{ - // enable/disable quadspi - void enable(); - void disable(); - - // init peripheral clock and GPIO - void init(); +// enable/disable quadspi +void enable(); +void disable(); - // abort any operation and reset configuration register (CCR) - void abort_reset(); +// init peripheral clock and GPIO +void init(); - // wait till the current operation is ended - void waitBusy(); - - // wait till all the expected bytes have been transferred - void waitTransfer(); +// abort any operation and reset configuration register (CCR) +void abort_reset(); -} +// wait till the current operation is ended +void waitBusy(); +// wait till all the expected bytes have been transferred +void waitTransfer(); -class qspi_flash { +} // namespace QSPI -public: +class qspi_flash +{ - // constructor +public: + // constructor qspi_flash(); - // init qspi peripheral and check ID flash - bool init(); - - // enable writing - void write_enable(); - - // disable writing - void write_disable(); + // init qspi peripheral which is connected to the flash + void init(); // read unique device ID - uint32_t readID(); + uint32_t readID(); - // erase the entire memory chip - THIS OPERATION MIGHT TAKE A WHILE!! - bool chip_erase(); + // erase the entire memory chip - THIS OPERATION MIGHT TAKE A WHILE!! + bool chip_erase(); - // erase the sector which contains the address (24 bit) specified - bool sector_erase(uint32_t address); + // erase the sector which contains the address (24 bit) specified + bool sector_erase(uint32_t address); // erase a block (32K) which contains the address (24 bit) specified - bool block32_erase(uint32_t address); + bool block32_erase(uint32_t address); // erase a block (32K) which contains the address (24 bit) specified - bool block64_erase(uint32_t address); + bool block64_erase(uint32_t address); - // read a byte at a specific address (24 bit) in memory - uint8_t read_byte(uint32_t address); + // 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); + // write a byte at a specific address (24 bit) in memory + bool byte_program(uint8_t data, uint32_t address); - // ATTENTION it may take a while! - makes the flash return to power-on default status. - void software_reset(); + // ATTENTION it may take a while! - makes the flash return to power-on + // default status. + void software_reset(); - // check if flash is executing some operation (program/erase or write registers) - bool isInProgress(); + // check last erase operation result + bool check_erase(); - // read security register of the flash - uint8_t read_security_reg(); + // check last program operation result + bool check_program(); - // read status register of the flash memory - uint8_t read_status_reg(); +private: + // enable writing + void write_enable(); -private: + // disable writing + void write_disable(); - // check last erase operation result - bool check_erase(); + // wait till flash has executed the current operation + void waitProgress(); - // check last program operation result - bool check_program(); + // check if flash is executing some operation (program/erase or write + // registers) + bool isInProgress(); + + // read security register of the flash + uint8_t read_security_reg(); - // wait till flash has executed the current operation - void waitProgress(); - - // most important flash memory commands + // read status register of the flash memory + uint8_t read_status_reg(); + + // most important flash memory commands enum Commands { - // read unique ID of the memory + // read unique ID of the memory READ_ID = 0x9F, - // write enable, needs to be executed before modify any data - WRITE_ENABLE = 0x06, - + // write enable, needs to be executed before modify any data + WRITE_ENABLE = 0x06, + // write disable - WRITE_DISABLE = 0x04, + WRITE_DISABLE = 0x04, - // read status register - READ_STATUS_REG = 0x05, + // read status register + READ_STATUS_REG = 0x05, - // write status register - WRITE_STATUS_REG = 0x01, + // write status register + WRITE_STATUS_REG = 0x01, // read secutity register - READ_SECURITY_REG = 0x2B, + READ_SECURITY_REG = 0x2B, - // read configuration register + // read configuration register READ_CONFIG_REGISTER = 0x15, - // read data from memory + // read data from memory READ = 0x03, // write a page on memory. PAGE_PROGRAM = 0x02, - // erase a specific sector of the memory - SECTOR_ERASE = 0x20, + // erase a specific sector of the memory + SECTOR_ERASE = 0x20, - // erase a specific block of 32KB of the memory - BLOCK_32_ERASE = 0x52, + // erase a specific block of 32KB of the memory + BLOCK_32_ERASE = 0x52, - // erase a specific block of 64KB of the memory - BLOCK_64_ERASE = 0xD8, + // erase a specific block of 64KB of the memory + BLOCK_64_ERASE = 0xD8, // erase all data on the chip - THIS COULD TAKE A LONG TIME ! ERASE_CHIP = 0xC7, @@ -169,5 +191,4 @@ private: // reset memory, reset enable command should be executed first RESET_MEMORY = 0x99 }; - }; \ No newline at end of file diff --git a/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp b/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp index ac63ed3ea..fea1e37ab 100644 --- a/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp +++ b/src/tests/drivers/QuadSpi-Flash/test-Qflash.cpp @@ -1,118 +1,132 @@ -// qspi-flash driver TEST, aggiunto l' eseguibile in cmakelist -// dipendenze: aggiunto qspi-flash.cpp in cmake.boardcore -// il test viene eseguito ma non sembra leggere l'ID - +/* Copyright (c) 2024 Skyward Experimental Rocketry + * Author: Valerio Flamminii + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "qspi-flash.h" qspi_flash mymemory; -int main() { - +int main() +{ // test readID() FUNZIONAAAA printf("starting ID test!\n"); - mymemory.init(); - - uint32_t ID = mymemory.readID(); + mymemory.init(); + + uint32_t ID = mymemory.readID(); - printf("ID: %x\n", ID); + printf("ID: %x\n", ID); - printf("end ID test\n"); + printf("end ID test\n"); - - // test write enable command FUNZIONAAAAAAA + // test write enable command FUNZIONAAAAAAA /* - printf("start write_enable command\n"); + printf("start write_enable command\n"); - mymemory.write_enable(); + mymemory.write_enable(); - printf("----- end write_enable command\n"); + printf("----- end write_enable command\n"); */ - - // test write disable command FUNZIONAAAAAAA - /* - printf("start write_disable command\n"); + + // test write disable command FUNZIONAAAAAAA + /* + printf("start write_disable command\n"); mymemory.write_disable(); printf("----- end write_disable command\n"); */ - // test funzione isInProgress + // test funzione isInProgress /* - printf("test funzione isInProgress()\n"); - + 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()); - */ + */ // test funzione sector erase SEMBRA FUNZIONARE FINO AD ORA !!!! /* - printf("\nstart TEST sector_erase()\n"); + printf("\nstart TEST sector_erase()\n"); printf("valore ritornato: %d\n", mymemory.sector_erase(0)); - printf("end test sector_erase()\n"); + printf("end test sector_erase()\n"); */ - // test funzione byte_program() - printf("\ntest funzione byte_program()\n"); + // test funzione byte_program() + printf("\ntest funzione byte_program()\n"); - printf("valore ritornato: %d\n", mymemory.byte_program(55U, 0)); + printf("valore ritornato: %d\n", mymemory.byte_program(55U, 0)); printf("end test byte_program()\n"); - // test funzione read_byte(): OCCHIO IMPOSTA SEMPRE LA DIMENSIONE DELLA FLASH + // test funzione read_byte(): OCCHIO IMPOSTA SEMPRE LA DIMENSIONE DELLA + // FLASH printf("\ntest funzione read_byte()\n"); - // test block32_erase(): FUNZIONA - printf("valore block32_erase(): %d\n", mymemory.block32_erase(0x3FFFFF)); + // test block32_erase(): FUNZIONA + printf("valore block32_erase(): %d\n", mymemory.block32_erase(0x3FFFFF)); + + // test block64_erase(): FUNZIONA + printf("valore block64_erase(): %d\n", mymemory.block64_erase(0x3fffff)); - // test block64_erase(): FUNZIONA - printf("valore block64_erase(): %d\n", mymemory.block64_erase(0x3fffff)); - printf("valore read_byte: %d\n", mymemory.read_byte(0)); - printf("----- end read_byte() test\n"); + printf("----- end read_byte() test\n"); - // test funzione reset(): FUNZIONA + // test funzione reset(): FUNZIONA /* - printf("\n------- start test funzione reset() ----------\n"); + printf("\n------- start test funzione reset() ----------\n"); - 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()); + 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()); - printf("------- end test funzione reset() ----------\n"); + printf("------- end test funzione reset() ----------\n"); */ - // test erase chip function(): FUNZIONA /* - printf("\nstart TEST erase chip function\n"); + printf("\nstart TEST erase chip function\n"); - printf("valore ritornato: %d\n", mymemory.chip_erase()); + printf("valore ritornato: %d\n", mymemory.chip_erase()); - printf("end of the erase chip operation.\n "); + printf("end of the erase chip operation.\n "); */ - // ------------- ATTENZIONE SU FUNZIONI DI LETTURA ----------------- + // ------------- 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 - + // 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 while (true) Thread::sleep(1000); -- GitLab