Перейти к содержанию
    

8 minutes ago, Forger said:

Это означает, что метод "копи-паст" тут только навредит, что собственно и вышло

Виноват) Исправлюсь)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С работой с 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 */

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прогресс на лицо !

Осталось совсем чуть-чуть.

Научится самому находить ответы на вопросы и можно учить студентов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё хотел спросить - а что означает?:

В 31.01.2020 в 01:48, MementoMori сказал:

у меня не такая qspi память, как в дисковери, а пара W25Q128JVSIQ с общим CS.

Думал уже и так и этак, но так и не допёр: как так "пара W25Q128JVSIQ с общим CS"?

Периферия STM32F746BG позволяет подключать две quad-SPI-флеши в параллель аки "8-битная шина" с общим CS?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, jcxz said:

Периферия STM32F746BG позволяет подключать две quad-SPI-флеши в параллель аки "8-битная шина" с общим CS?

Да.

N8c2gnUK.png

 

 

Но хочу отметить - я сейчас работаю только с одной флеш. Пока что. 

Подозреваю что что-то не так с 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, &reg, 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, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return QSPI_ERROR;
  }
  
  return QSPI_OK;
}

В винбондовской такого регистра нет. И как эту функцию перенастроить под W25Q128 - я пока не пойму. Но - ее отключение при работе с микроновской памятью ни к каким последствиям не приводит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

 

Вернемся к алгоритму, в который я попытался вставить код для микросхемы, с которой нет проблем, то есть n25q128, ее же и пытаюсь прошить алгоритмом через кейл.

On 2/2/2020 at 11:40 PM, Forger said:

) сделал бы минимально необходимый проект загрузчика, где запись шла бы не во внешнюю QSPI, а вообще никуда, формально. Функции записи чтения - пустые, но возвращают всегда, что все ОК.

У меня почему-то кроме init не вызывается ни одна функция шаблона. Я убрал весь код, кроме того, что необходим для включения светодиода. В каждую функцию шаблона я вставил строку включения светодиода. После нее return 0. Светодиод зажигается лишь, если его включать из init. Остальные функции не вызываются.

Вы писали о простейших и пустых функциях, которые возвращают ок (или "0"). В шаблоне, который есть в кейле, по сути так и сделано - там во всех четырех функциях пусто и каждая из них возвращает 0.

Я правильно понимаю, что если этот пустой алгоритм скомпилировать то при попытке прошить флеш она не прошьется по факту, но кейл подумает, что все ОК? У меня подклбючение хоть изначального шаблона, хоть шаблона со вставленными функциями выдает ошибку истечения таймаута.

Разве кейлу недостаточно того, что функции шаблона возвращают 0 ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я вроде бы простой вопрос задал. Не спрашивал, что у меня не так. Спросил лишь, как должно быть и правильно ли я понимаю логику работы системы. 

А вам бы поглумиться...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, MementoMori said:

Я вроде бы простой вопрос задал.

ВопросЫ, куча вопросов. Ответы на эти в целом риторические вопросы вы вполне можете найти самостоятельно. Неоднократно тут об этом писалось.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, Forger said:

Ответы на эти в целом риторические вопросы вы вполне можете найти самостоятельно. Неоднократно тут об этом писалось.

Да вы что? И ответ на вопрос, начинающийся словами "правильно ли я понимаю..", тоже в мануалах имеется?  

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, MementoMori said:

Да вы что? И ответ на вопрос, начинающийся словами "правильно ли я понимаю..", тоже в мануалах имеется?  

Ответ на свои риторические вопросы вы можете сформировать самостоятельно, после более вдумчивого чтения мануала. 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может хватит уже из меня дурака делать?

Я перечитал мануал, посмотрел примеры.

Пожалуйста.  Из подпапки 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 - дебаггер (что мне кажется более логичным) или программист, прописывая вызовы этих функций черти где, непонятно. У меня дебаггер их не вызывает.

Вы в самом деле считаете что все настолько прозрачно и понятно, что об этом стыдно спрашивать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

21 minutes ago, MementoMori said:

Может хватит уже из меня дурака делать?

Несколько лет назад мне пришлось пройти тем же путем, правда, флешка была SPI от атмел, камень STM32. Управился за один рабочий день. Уверен, тут многие и быстрее решат такую в целом тривиальную задачу.

Разбирался по примерам и мануалу из keil.

 

27 minutes ago, MementoMori said:

Вы в самом деле считаете что все настолько прозрачно и понятно, что об этом стыдно спрашивать?

Да

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

21 minutes ago, Forger said:

Разбирался по примерам и мануалу из keil.

А проблема невызова функций не возникала? Или возникала, но вы ее решили по мануалу?  В котором, по вашему, она описана и приведен способ ее решения?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, MementoMori said:

А проблема невызова функций не возникала?

Нет. Чтобы указанные функции не вызывались, нужно просто избегать обращения к соотв. области памяти, т. е. линкером ничего там не размещать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...