petrdynin

Mik32+FlashToRam+SelfProgramFlash+RamToFlash

Sep 22nd, 2025
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.11 KB | Source Code | 0 0
  1. #include "mik32_hal_pcc.h"
  2. #include "mik32_hal_gpio.h"
  3. #include "mik32_hal_spifi_w25.h"
  4.  
  5. /*
  6.  * Программа демонстрирует переход из FLASH в RAM и обратно
  7.  * FLASH (QPI+XIP) -> RAM (write_flash) RAM -> FLASH (QPI+XIP)
  8.  * Сначала переводим микросхему W25Q64 в режим работы с периферией,
  9.  * затем переводим ее в режим работы с командами и проверяем
  10.  * успешность перехода чтением JDEC ID (0x60), пробуем
  11.  * стереть последний сектор флеши и затем в первую страницу последнего
  12.  * сектора записываем тестовые данные, затем снова возвращаем режим QPI+XIP
  13.  * и возвращаемся к первоначальной работе из флеш.
  14.  * Все переходы сопровождаются миганием светодиодов.
  15.  * Результат записи во флеш можно увидеть в отладчике по адресу 0х801FF000
  16.  * после возвращения в режим работы с памятью
  17.  */
  18.  
  19. void SystemClock_Config();
  20. void GPIO_Init();
  21. void flash_write_page_qpi(void);
  22. int SPIFI_WaitIntrqTimeout(uint32_t timeout);
  23. uint32_t  get_flash_usage_end(void);
  24. bool is_sector_free(uint32_t sector_address);
  25. uint8_t read_sreg_1(void);
  26. bool w25q_is_busy(uint32_t timeout);
  27. void write_enable(void);
  28. void w25q_sector_erase(uint32_t address);
  29. void page_program(unsigned int ByteAddress, uint8_t data[], int byte_count);
  30. bool write_to_last_sector(uint8_t *data);
  31.  
  32.  
  33. #define TIMEOUT            100000
  34.  
  35. #define FLASH_TOTAL_SIZE   (2 * 1024 * 1024)
  36. #define FLASH_BASE_ADDRESS 0x80000000
  37. #define SECTOR_SIZE 4096
  38. #define PAGE_SIZE 256
  39.  
  40. volatile uint8_t jedec_id_qpi[3] = {0};
  41.  
  42. extern uint32_t __DATA_IMAGE_END__;
  43. extern uint32_t __TEXT_END__;
  44.  
  45.  
  46. int main()
  47. {
  48.     SystemClock_Config();
  49.     GPIO_Init();
  50.  
  51.     flash_write_page_qpi();
  52.  
  53.     while (1)
  54.     {
  55.         // если мы попали сюда, значит мы успешно поработали с FLASH
  56.         // из RAM и снова вернулись к работе программы из FLASH
  57.         // и в отладчике теперь можно просмотреть результат записи
  58.         HAL_GPIO_TogglePin(GPIO_0, GPIO_PIN_9 | GPIO_PIN_10);
  59.         HAL_DelayMs(700);
  60.     }
  61. }
  62.  
  63. void SystemClock_Config(void)
  64. {
  65.     PCC_InitTypeDef PCC_OscInit = {0};
  66.  
  67.     PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
  68.     PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
  69.     PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
  70.     PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
  71.     PCC_OscInit.AHBDivider = 0;
  72.     PCC_OscInit.APBMDivider = 0;
  73.     PCC_OscInit.APBPDivider = 0;
  74.     PCC_OscInit.HSI32MCalibrationValue = 128;
  75.     PCC_OscInit.LSI32KCalibrationValue = 8;
  76.     PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
  77.     PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
  78.     HAL_PCC_Config(&PCC_OscInit);
  79. }
  80.  
  81. void GPIO_Init()
  82. {
  83.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  84.  
  85.     __HAL_PCC_GPIO_0_CLK_ENABLE();
  86.  
  87.     GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
  88.     GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_OUTPUT;
  89.     GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
  90.    
  91.     HAL_GPIO_Init(GPIO_0, &GPIO_InitStruct);
  92. }
  93.  
  94.  
  95. void __attribute__((used, section(".ram_text"))) flash_write_page_qpi(void)
  96. {
  97.   // мы сейчас с флеш точно работаем XIP + QPI, но перешли в ОЗУ и теперь нужно уйти из XIP,
  98.   // т.е работали в режиме памяти, для этого надо перейти в режим периферии
  99.   // сначала делаем сброс текущей команды работы в режиме памяти
  100.  
  101.     SPIFI_CONFIG->STAT = SPIFI_CONFIG_STAT_RESET_M;
  102.  
  103.     //выводим QPI из "без команд" в режим "с командами"
  104.     const uint32_t cmd_chip_qpi_w_cmd =
  105.         SPIFI_DIRECTION_INPUT |
  106.         SPIFI_CONFIG_CMD_INTLEN(1) |
  107.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  108.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_3ADDR) |  /* нет кода операции, 3 адреса  */
  109.         SPIFI_CONFIG_CMD_OPCODE(0xEB);
  110.  
  111.     SPIFI_CONFIG->ADDR  = 0;
  112.     SPIFI_CONFIG->IDATA = 0;
  113.     SPIFI_CONFIG->CMD   = cmd_chip_qpi_w_cmd;
  114.     if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
  115.             SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; //  команда выполнена, выставлен IRQ, сбросим IRQ
  116.          }
  117.     else {
  118.         asm("nop"); // таймаут, что-то пошло не так
  119.        }
  120.  
  121.     // контрольная проверка принимает ли флеш команды или нет, для этого пробуем прочитать JDEC ID
  122.     const uint32_t cmd_jedec_qpi =
  123.         SPIFI_DIRECTION_INPUT |
  124.         SPIFI_CONFIG_CMD_INTLEN(0) |
  125.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  126.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE) |
  127.         SPIFI_CONFIG_CMD_OPCODE(0x9F);
  128.  
  129.     SPIFI_CONFIG->ADDR  = 0;
  130.     SPIFI_CONFIG->IDATA = 0;
  131.     SPIFI_CONFIG->CMD   = cmd_jedec_qpi | SPIFI_CONFIG_CMD_DATALEN(3);
  132.     if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
  133.          SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // сбросим IRQ
  134.         }
  135.     else {
  136.         asm("nop"); // таймаут, что-то пошло не так
  137.           }
  138.  
  139.       for (int i = 0; i < 3; i++)
  140.          jedec_id_qpi[i] =  SPIFI_CONFIG->DATA8;
  141.  
  142.       // если успешно прочитали JDEC ID, то поморгаем вразнобой
  143.       if(jedec_id_qpi[1] == 0x60){
  144.           for(int i=0; i<16; i++)
  145.               {
  146.                  GPIO_0->OUTPUT ^= 1<<9;
  147.                  for(int i=0; i<500000; i++)
  148.                     {
  149.                        asm("nop");
  150.                     }
  151.                  GPIO_0->OUTPUT ^= 1<<10;
  152.                  for(int i=0; i<500000; i++)
  153.                     {
  154.                        asm("nop");
  155.                     }
  156.                 }
  157.            }
  158.       for(int i=0; i<500000; i++){
  159.                    asm("nop");
  160.                  }
  161.  
  162.     //***** пробуем стереть и записать первую страницу последнего сектора ******
  163.  
  164.     uint8_t my_data[PAGE_SIZE];
  165.     // формируем данные для записи
  166.     for(int i=0; i<PAGE_SIZE; i++)
  167.         my_data[i] = i;
  168.  
  169.     if (write_to_last_sector(my_data)) {
  170.          // стирание и запись прошли успешно
  171.        }
  172.  
  173.     //*************************************************************************
  174.  
  175.     //вернем назад QPI из режима "с командами" в режим "без команд"
  176.     const uint32_t cmd_chip_qpi_wo_cmd =
  177.         SPIFI_DIRECTION_INPUT |
  178.         SPIFI_CONFIG_CMD_INTLEN(1) |
  179.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  180.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE_3ADDR) |  /* есть код операции, 3 адреса  */
  181.         SPIFI_CONFIG_CMD_OPCODE(0xEB);
  182.  
  183.     SPIFI_CONFIG->ADDR  = 0;
  184.     SPIFI_CONFIG->IDATA = 0x20;
  185.     SPIFI_CONFIG->CMD  = cmd_chip_qpi_wo_cmd;
  186.     if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
  187.               SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; //  команда выполнена, выставлен IRQ, сбросим IRQ
  188.          }
  189.     else {
  190.         asm("nop"); // таймаут, что-то пошло не так
  191.          }
  192.  
  193.      // а теперь вернем SPIFI в режим работы с памятью
  194.      // настройки кэш не трогаем, они не изменились
  195.  
  196.      const uint32_t mcmd_chip_qpi_wo_cmd =
  197.         SPIFI_DIRECTION_INPUT |
  198.         SPIFI_CONFIG_CMD_INTLEN(1) |
  199.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  200.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_3ADDR) |  /* нет кода операции, 3 адреса  */
  201.         SPIFI_CONFIG_CMD_OPCODE(0xEB);
  202.  
  203.     SPIFI_CONFIG->ADDR  = 0;
  204.     SPIFI_CONFIG->IDATA = 0x20;
  205.     SPIFI_CONFIG->MCMD  = mcmd_chip_qpi_wo_cmd;
  206.     if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
  207.        SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; //  команда выполнена, выставлен IRQ, сбросим IRQ
  208.     }
  209.     else {
  210.          asm("nop"); // таймаут, что-то пошло не так
  211.     }
  212.  
  213.     // поморгали перед выходом из ОЗУ, если настройки правильные,
  214.     // то после этого мы вернемся к работе программы из флеш
  215.     GPIO_0->OUTPUT ^= 1<<9 | 1<<10;
  216.     for(int i=0; i<16; i++)
  217.      {
  218.         GPIO_0->OUTPUT ^= 1<<9 | 1<<10;
  219.         for(int i=0; i<500000; i++){
  220.            asm("nop");
  221.          }
  222.      }
  223. }
  224.  
  225. //*****************************************************************************
  226. // Получить конец используемой флеш-памяти
  227. __attribute__((used, section(".ram_text")))
  228. uint32_t  get_flash_usage_end(void) {
  229.     // Используем максимальный адрес между концом кода и концом данных
  230.     uint32_t code_end = (uint32_t)&__TEXT_END__;
  231.     uint32_t data_end = (uint32_t)&__DATA_IMAGE_END__;
  232.     return (code_end > data_end) ? code_end : data_end;
  233. }
  234.  
  235. //*****************************************************************************
  236. // Проверить, свободен ли сектор
  237. __attribute__((used, section(".ram_text")))
  238. bool is_sector_free(uint32_t sector_address) {
  239.     // Сектор свободен, если он находится за пределами используемой памяти
  240.     uint32_t usage_end = get_flash_usage_end();
  241.     return (sector_address >= usage_end);
  242. }
  243.  
  244. //*****************************************************************************
  245. __attribute__((used, section(".ram_text")))
  246. uint8_t read_sreg_1(void)
  247. {
  248.     static uint8_t read_sreg = 0;
  249.  
  250.     const uint32_t cmd_read_sreg1 =
  251.         SPIFI_DIRECTION_INPUT |
  252.         SPIFI_CONFIG_CMD_INTLEN(0) |
  253.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  254.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE) |
  255.         SPIFI_CONFIG_CMD_OPCODE(0x05);
  256.  
  257.     SPIFI_CONFIG->CMD   = cmd_read_sreg1 | SPIFI_CONFIG_CMD_DATALEN(1);
  258.     if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
  259.          SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // сбросим IRQ
  260.         }
  261.     else {
  262.         asm("nop"); // таймаут, что-то пошло не так
  263.         return 0;
  264.      }
  265.  
  266.     read_sreg = SPIFI_CONFIG->DATA8;
  267.     return read_sreg;
  268.  
  269. }
  270.  
  271. //*****************************************************************************
  272. __attribute__((used, section(".ram_text")))
  273. bool w25q_is_busy(uint32_t timeout){
  274.  
  275.  while (timeout-- != 0)
  276.     {
  277.         if ((read_sreg_1() & 1) == 0)
  278.         {
  279.             asm("nop");
  280.             return 0;
  281.         }
  282.     }
  283.     return 1;
  284. }
  285.  
  286. //*****************************************************************************
  287. __attribute__((used, section(".ram_text")))
  288. void write_enable(void)
  289. {
  290.     const uint32_t cmd_write_enable =
  291.         SPIFI_DIRECTION_INPUT |
  292.         SPIFI_CONFIG_CMD_INTLEN(0) |
  293.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  294.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE) |
  295.         SPIFI_CONFIG_CMD_OPCODE(0x06);
  296.  
  297.     SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
  298.     SPIFI_CONFIG->CMD = cmd_write_enable;
  299.     if(SPIFI_WaitIntrqTimeout(TIMEOUT) == 0)
  300.     {
  301.          return;
  302.     }
  303. }
  304.  
  305. //*****************************************************************************
  306. __attribute__((used, section(".ram_text")))
  307. void w25q_sector_erase(uint32_t address){
  308.  
  309.     write_enable();
  310.  
  311.     const uint32_t cmd_sector_erase_4k =
  312.         SPIFI_DIRECTION_INPUT |
  313.         SPIFI_CONFIG_CMD_INTLEN(0) |
  314.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  315.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE_3ADDR) |
  316.         SPIFI_CONFIG_CMD_OPCODE(0x20);
  317.  
  318.      SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
  319.      SPIFI_CONFIG->ADDR = address;
  320.      SPIFI_CONFIG->CMD = cmd_sector_erase_4k;
  321.      if(SPIFI_WaitIntrqTimeout(TIMEOUT) == 0)
  322.        {
  323.            return;
  324.        }
  325. }
  326.  
  327. //*****************************************************************************
  328. __attribute__((used, section(".ram_text")))
  329. void page_program(unsigned int ByteAddress, uint8_t data[], int byte_count)  {
  330.  
  331.     if(byte_count > 256)
  332.     {
  333.        return;
  334.     }
  335.  
  336.     SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
  337.     SPIFI_CONFIG->ADDR = ByteAddress;
  338.     SPIFI_CONFIG->IDATA = 0x00;
  339.  
  340.     const uint32_t cmd_page_program =
  341.         SPIFI_DIRECTION_OUTPUT |
  342.         SPIFI_CONFIG_CMD_INTLEN(0) |
  343.         SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
  344.         SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE_3ADDR) |
  345.         SPIFI_CONFIG_CMD_OPCODE(0x02);
  346.     SPIFI_CONFIG->CMD  = cmd_page_program | SPIFI_CONFIG_CMD_DATALEN(byte_count);
  347.  
  348.     for(int i = 0; i < byte_count; i++)
  349.     {
  350.         SPIFI_CONFIG->DATA8 = data[i];
  351.     }
  352.  
  353.     SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
  354. }
  355.  
  356. //*****************************************************************************
  357. __attribute__((used, section(".ram_text")))
  358. bool write_to_last_sector(uint8_t *data){
  359.     // Определяем адрес последнего сектора
  360.     uint32_t last_sector_address = FLASH_BASE_ADDRESS + FLASH_TOTAL_SIZE - SECTOR_SIZE;
  361.  
  362.     // Проверяем, свободен ли сектор
  363.     if (!is_sector_free(last_sector_address)) {
  364.         // Сектор занят - нельзя использовать
  365.         return 0;
  366.     }
  367.  
  368.     // Стираем сектор (это необходимо перед записью)
  369.     w25q_sector_erase(last_sector_address);
  370.     if(w25q_is_busy(TIMEOUT) == 1){
  371.         return 0;
  372.       }
  373.  
  374.     write_enable();
  375.     page_program(last_sector_address, data, PAGE_SIZE);
  376.     if(w25q_is_busy(TIMEOUT) == 1){
  377.             return 0;
  378.         }
  379.  
  380.  return 1;
  381. }
  382.  
  383. //*****************************************************************************
  384. int __attribute__((used, section(".ram_text"))) SPIFI_WaitIntrqTimeout(uint32_t timeout)
  385.     {
  386.         while (timeout-- > 0)
  387.         {
  388.             if((SPIFI_CONFIG->STAT & SPIFI_CONFIG_STAT_INTRQ_M) != 0)
  389.             {
  390.                 return 1;
  391.             }
  392.         }
  393.         return 0;
  394.     }
  395.  
  396. //*****************************************************************************
  397.  
Advertisement
Add Comment
Please, Sign In to add comment