MementoMori 4 3 февраля, 2020 Опубликовано 3 февраля, 2020 · Жалоба 8 minutes ago, Forger said: Это означает, что метод "копи-паст" тут только навредит, что собственно и вышло Виноват) Исправлюсь) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 4 февраля, 2020 Опубликовано 4 февраля, 2020 · Жалоба С работой с QSPI разобрался. На плате DISCO есть n25q128 (https://www.farnell.com/datasheets/1674445.pdf) - чтение, запись, блоками, страницами, стирание целиком, все, что нужно для алгоритма, работает. Дело за малым - с учетом отличий, адаптировать код под другую микросхему - W25Q128JV ( https://www.winbond.com/resource-files/w25q128jv revf 03272018 plus.pdf ). Микросхемы по структуре, принципам работы и даже распиновке идентичны. И имеющаяся у меня библиотека под N25Q128 вполне себе с ней работает. Я читал регистры (о производителе, статусные регистры) - программа выдает адекватные данные. Проверяю просто for (uint16_t i=0;i<256;i++) WRITE_BUF[i]=i; RESULT3=BSP_QSPI_Write(WRITE_BUF, 0x00000100, 256); HAL_Delay(100); RESULT4=BSP_QSPI_Read(READ_BUF, 0x00000100, 256); Функции стирания чипа, записи блока, чтения из блока ошибок не возвращают. С одним лишь но. Все прочитанные байты равны 0xFF. Даже не пойму, что сбоит - чтение или запись или все вместе. Какие либо ошибки программы или монтажа на своей плате исключаю по одной простой причине - меняю друг с другом микросхемы памяти на дискавери и на своей плате - дискавери bp w25q128 читает 0xFF, моя плата с напаянной n25q128 работает нормально. Значит чем-то эти микросхемы отличаются, а какое именно отличие играет роль - я не пойму. Полез я (еще до перепаек) в дефайны. Да, они отличаются, но лишь теми регистрами, которые в функциях чтения и записи не затронуты. Вот дефайны W25Q128 ( ----------------- - то что отличается, ========= - то что отличается только названием, но суть и значения те же, ++++++ - то, что есть в одной микросхеме и нет в другой) #define W25Q128FV_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */ #define W25Q128FV_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */ #define W25Q128FV_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */ #define W25Q128FV_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */ #define W25Q128FV_DUMMY_CYCLES_READ 4 -------- #define W25Q128FV_DUMMY_CYCLES_READ_QUAD 10 #define W25Q128FV_BULK_ERASE_MAX_TIME 250000 #define W25Q128FV_SECTOR_ERASE_MAX_TIME 3000 #define W25Q128FV_SUBSECTOR_ERASE_MAX_TIME 800 /** * @brief W25Q128FV Commands */ /* Reset Operations */ #define RESET_ENABLE_CMD 0x66 #define RESET_MEMORY_CMD 0x99 #define ENTER_QPI_MODE_CMD 0x38 #define EXIT_QPI_MODE_CMD 0xFF /* Identification Operations */ #define READ_ID_CMD 0x90 ----------- #define DUAL_READ_ID_CMD 0x92 ++++++++++ #define QUAD_READ_ID_CMD 0x94 +++++++++ #define READ_JEDEC_ID_CMD 0x9F =========== /* Read Operations */ #define READ_CMD 0x03 #define FAST_READ_CMD 0x0B #define DUAL_OUT_FAST_READ_CMD 0x3B #define DUAL_INOUT_FAST_READ_CMD 0xBB #define QUAD_OUT_FAST_READ_CMD 0x6B #define QUAD_INOUT_FAST_READ_CMD 0xEB /* Write Operations */ #define WRITE_ENABLE_CMD 0x06 #define WRITE_DISABLE_CMD 0x04 /* Register Operations */ #define READ_STATUS_REG1_CMD 0x05 ======== #define READ_STATUS_REG2_CMD 0x35 ++++++++ #define READ_STATUS_REG3_CMD 0x15 ++++++++ #define WRITE_STATUS_REG1_CMD 0x01 ======== #define WRITE_STATUS_REG2_CMD 0x31 +++++++ #define WRITE_STATUS_REG3_CMD 0x11 +++++++ /* Program Operations */ #define PAGE_PROG_CMD 0x02 #define QUAD_INPUT_PAGE_PROG_CMD 0x32 ========== /* Erase Operations */ #define SECTOR_ERASE_CMD 0x20 ========= #define CHIP_ERASE_CMD 0xC7 ========== #define PROG_ERASE_RESUME_CMD 0x7A #define PROG_ERASE_SUSPEND_CMD 0x75 /* Flag Status Register */ #define W25Q128FV_FSR_BUSY ((uint8_t)0x01) /*!< busy */ #define W25Q128FV_FSR_WREN ((uint8_t)0x02) /*!< write enable */ #define W25Q128FV_FSR_QE ((uint8_t)0x02) /*!< quad enable */ Вот дефайны N25Q128 #define N25Q128A_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */ #define N25Q128A_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */ #define N25Q128A_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */ #define N25Q128A_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */ #define N25Q128A_DUMMY_CYCLES_READ 8 --------- #define N25Q128A_DUMMY_CYCLES_READ_QUAD 10 #define N25Q128A_BULK_ERASE_MAX_TIME 250000 #define N25Q128A_SECTOR_ERASE_MAX_TIME 3000 #define N25Q128A_SUBSECTOR_ERASE_MAX_TIME 800 /** * @brief N25Q128A Commands */ /* Reset Operations */ #define RESET_ENABLE_CMD 0x66 #define RESET_MEMORY_CMD 0x99 /* Identification Operations */ #define READ_ID_CMD 0x9E ----------- #define READ_ID_CMD2 0x9F ============ #define MULTIPLE_IO_READ_ID_CMD 0xAF +++++++++ #define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A ++++++++++ /* Read Operations */ #define READ_CMD 0x03 #define FAST_READ_CMD 0x0B #define DUAL_OUT_FAST_READ_CMD 0x3B #define DUAL_INOUT_FAST_READ_CMD 0xBB #define QUAD_OUT_FAST_READ_CMD 0x6B #define QUAD_INOUT_FAST_READ_CMD 0xEB /* Write Operations */ #define WRITE_ENABLE_CMD 0x06 #define WRITE_DISABLE_CMD 0x04 /* Register Operations */ #define READ_STATUS_REG_CMD 0x05 ========= #define WRITE_STATUS_REG_CMD 0x01 ========= #define READ_LOCK_REG_CMD 0xE8 +++++ #define WRITE_LOCK_REG_CMD 0xE5 +++++ #define READ_FLAG_STATUS_REG_CMD 0x70 +++++ #define CLEAR_FLAG_STATUS_REG_CMD 0x50 +++++ #define READ_NONVOL_CFG_REG_CMD 0xB5 +++++ #define WRITE_NONVOL_CFG_REG_CMD 0xB1 +++++ #define READ_VOL_CFG_REG_CMD 0x85 ++++++ #define WRITE_VOL_CFG_REG_CMD 0x81 ++++++ #define READ_ENHANCED_VOL_CFG_REG_CMD 0x65 +++++ #define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61 ++++++ /* Program Operations */ #define PAGE_PROG_CMD 0x02 #define DUAL_IN_FAST_PROG_CMD 0xA2 #define EXT_DUAL_IN_FAST_PROG_CMD 0xD2 #define QUAD_IN_FAST_PROG_CMD 0x32 ======== #define EXT_QUAD_IN_FAST_PROG_CMD 0x12 /* Erase Operations */ #define SUBSECTOR_ERASE_CMD 0x20 ++++++++++ #define SECTOR_ERASE_CMD 0xD8 =========== #define BULK_ERASE_CMD 0xC7 =========== #define PROG_ERASE_RESUME_CMD 0x7A #define PROG_ERASE_SUSPEND_CMD 0x75 /* One-Time Programmable Operations */ #define READ_OTP_ARRAY_CMD 0x4B +++++++++ #define PROG_OTP_ARRAY_CMD 0x42 +++++++++ /** * @brief N25Q128A Registers */ /* Status Register */ #define N25Q128A_SR_WIP ((uint8_t)0x01) /*!< Write in progress */ #define N25Q128A_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */ #define N25Q128A_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */ #define N25Q128A_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */ #define N25Q128A_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */ /* Nonvolatile Configuration Register */ #define N25Q128A_NVCR_LOCK ((uint16_t)0x0001) /*!< Lock nonvolatile configuration register */ #define N25Q128A_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */ #define N25Q128A_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */ #define N25Q128A_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */ #define N25Q128A_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */ #define N25Q128A_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */ #define N25Q128A_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */ /* Volatile Configuration Register */ #define N25Q128A_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */ #define N25Q128A_VCR_XIP ((uint8_t)0x08) /*!< XIP */ #define N25Q128A_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */ /* Enhanced Volatile Configuration Register */ #define N25Q128A_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */ #define N25Q128A_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */ #define N25Q128A_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */ #define N25Q128A_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */ #define N25Q128A_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */ /* Flag Status Register */ #define N25Q128A_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */ #define N25Q128A_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */ #define N25Q128A_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */ #define N25Q128A_FSR_PGERR ((uint8_t)0x10) /*!< Program error */ #define N25Q128A_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */ #define N25Q128A_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */ #define N25Q128A_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 4 февраля, 2020 Опубликовано 4 февраля, 2020 · Жалоба Прогресс на лицо ! Осталось совсем чуть-чуть. Научится самому находить ответы на вопросы и можно учить студентов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 4 февраля, 2020 Опубликовано 4 февраля, 2020 · Жалоба Всё хотел спросить - а что означает?: В 31.01.2020 в 01:48, MementoMori сказал: у меня не такая qspi память, как в дисковери, а пара W25Q128JVSIQ с общим CS. Думал уже и так и этак, но так и не допёр: как так "пара W25Q128JVSIQ с общим CS"? Периферия STM32F746BG позволяет подключать две quad-SPI-флеши в параллель аки "8-битная шина" с общим CS? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 4 февраля, 2020 Опубликовано 4 февраля, 2020 · Жалоба 1 minute ago, jcxz said: Периферия STM32F746BG позволяет подключать две quad-SPI-флеши в параллель аки "8-битная шина" с общим CS? Да. Но хочу отметить - я сейчас работаю только с одной флеш. Пока что. Подозреваю что что-то не так с Dymmy cycles. В микроновской памяти есть такой вот регистр - READ VOLATILE CONFIGURATION REGISTER 85h (стр.27 даташита) Общение с ним такое: static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef s_command; uint8_t reg; /* Initialize the read volatile configuration register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_VOL_CFG_REG_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Enable write operations */ if (QSPI_WriteEnable(hqspi) != QSPI_OK) { return QSPI_ERROR; } /* Update volatile configuration register (with new dummy cycles) */ s_command.Instruction = WRITE_VOL_CFG_REG_CMD; MODIFY_REG(reg, N25Q128A_VCR_NB_DUMMY, (N25Q128A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q128A_VCR_NB_DUMMY))); /* Configure the write volatile configuration register command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data */ if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; } В винбондовской такого регистра нет. И как эту функцию перенастроить под W25Q128 - я пока не пойму. Но - ее отключение при работе с микроновской памятью ни к каким последствиям не приводит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба Вернемся к алгоритму, в который я попытался вставить код для микросхемы, с которой нет проблем, то есть n25q128, ее же и пытаюсь прошить алгоритмом через кейл. On 2/2/2020 at 11:40 PM, Forger said: ) сделал бы минимально необходимый проект загрузчика, где запись шла бы не во внешнюю QSPI, а вообще никуда, формально. Функции записи чтения - пустые, но возвращают всегда, что все ОК. У меня почему-то кроме init не вызывается ни одна функция шаблона. Я убрал весь код, кроме того, что необходим для включения светодиода. В каждую функцию шаблона я вставил строку включения светодиода. После нее return 0. Светодиод зажигается лишь, если его включать из init. Остальные функции не вызываются. Вы писали о простейших и пустых функциях, которые возвращают ок (или "0"). В шаблоне, который есть в кейле, по сути так и сделано - там во всех четырех функциях пусто и каждая из них возвращает 0. Я правильно понимаю, что если этот пустой алгоритм скомпилировать то при попытке прошить флеш она не прошьется по факту, но кейл подумает, что все ОК? У меня подклбючение хоть изначального шаблона, хоть шаблона со вставленными функциями выдает ошибку истечения таймаута. Разве кейлу недостаточно того, что функции шаблона возвращают 0 ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 11 hours ago, x893 said: Прогресс на лицо ! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба Я вроде бы простой вопрос задал. Не спрашивал, что у меня не так. Спросил лишь, как должно быть и правильно ли я понимаю логику работы системы. А вам бы поглумиться... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 3 minutes ago, MementoMori said: Я вроде бы простой вопрос задал. ВопросЫ, куча вопросов. Ответы на эти в целом риторические вопросы вы вполне можете найти самостоятельно. Неоднократно тут об этом писалось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 4 minutes ago, Forger said: Ответы на эти в целом риторические вопросы вы вполне можете найти самостоятельно. Неоднократно тут об этом писалось. Да вы что? И ответ на вопрос, начинающийся словами "правильно ли я понимаю..", тоже в мануалах имеется? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 4 minutes ago, MementoMori said: Да вы что? И ответ на вопрос, начинающийся словами "правильно ли я понимаю..", тоже в мануалах имеется? Ответ на свои риторические вопросы вы можете сформировать самостоятельно, после более вдумчивого чтения мануала. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба Может хватит уже из меня дурака делать? Я перечитал мануал, посмотрел примеры. Пожалуйста. Из подпапки Test, что в папке с шаблоном /* Test EraseSector Function -----------------------------------------------*/ ret = Init(0x08000000, 8000000, 1); // Initialize Flash Programming Functions // Device Base Address = 0x08000000 // Clock Frequency = 8MHz for (n = FlashDevice.DevAdr; n < (FlashDevice.DevAdr + FlashDevice.szDev); n += FlashDevice.szPage) { ret |= EraseSector(n); // Test Sector Erase } // Verify Erase for (n = 0; n < FlashDevice.szDev; n++) { if (M8(FlashDevice.DevAdr + n) != FlashDevice.valEmpty) { ret = 1; // Error break; } } ret |= UnInit (1); // Uninitialize Flash Programming Functions /* Test ProgramPage Function -----------------------------------------------*/ ret |= Init(0x08000000, 8000000, 2); // Initialize Flash Programming Functions for (n = FlashDevice.DevAdr; n < (FlashDevice.DevAdr + FlashDevice.szDev); n += FlashDevice.szPage) { ret |= ProgramPage(n, FlashDevice.szPage, buf); // Test Page Programming } Казалось бы, ура! Вот оно. В функцию init подставляешь параметр, которым определяется действие - стирать или писать и все. Лезем в функцию init - и что видим int Init (unsigned long adr, unsigned long clk, unsigned long fnc) { base_adr = adr & ~(BANK1_SIZE - 1); // Align to Size Boundary // Zero Wait State FLASH->ACR = 0x00000000; // Unlock Flash FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; #ifdef STM32F10x_1024 FLASH->KEYR2 = FLASH_KEY1; // Flash bank 2 FLASH->KEYR2 = FLASH_KEY2; #endif // Test if IWDG is running (IWDG in HW mode) if ((FLASH->OBR & 0x04) == 0x00) { // Set IWDG time out to ~32.768 second IWDG->KR = 0x5555; // Enable write access to IWDG_PR and IWDG_RLR IWDG->PR = 0x06; // Set prescaler to 256 IWDG->RLR = 4095; // Set reload value to 4095 } return (0); } Анализом параметров fnc и clk даже не пахнет. И это не шаблон, это пример. Кто вызывает ProgramPage, EraseSector - дебаггер (что мне кажется более логичным) или программист, прописывая вызовы этих функций черти где, непонятно. У меня дебаггер их не вызывает. Вы в самом деле считаете что все настолько прозрачно и понятно, что об этом стыдно спрашивать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 21 minutes ago, MementoMori said: Может хватит уже из меня дурака делать? Несколько лет назад мне пришлось пройти тем же путем, правда, флешка была SPI от атмел, камень STM32. Управился за один рабочий день. Уверен, тут многие и быстрее решат такую в целом тривиальную задачу. Разбирался по примерам и мануалу из keil. 27 minutes ago, MementoMori said: Вы в самом деле считаете что все настолько прозрачно и понятно, что об этом стыдно спрашивать? Да Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MementoMori 4 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 21 minutes ago, Forger said: Разбирался по примерам и мануалу из keil. А проблема невызова функций не возникала? Или возникала, но вы ее решили по мануалу? В котором, по вашему, она описана и приведен способ ее решения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 5 февраля, 2020 Опубликовано 5 февраля, 2020 · Жалоба 6 minutes ago, MementoMori said: А проблема невызова функций не возникала? Нет. Чтобы указанные функции не вызывались, нужно просто избегать обращения к соотв. области памяти, т. е. линкером ничего там не размещать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться