Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "mik32_hal_pcc.h"
- #include "mik32_hal_gpio.h"
- #include "mik32_hal_spifi_w25.h"
- /*
- * Программа демонстрирует переход из FLASH в RAM и обратно
- * FLASH (QPI+XIP) -> RAM (write_flash) RAM -> FLASH (QPI+XIP)
- * Сначала переводим микросхему W25Q64 в режим работы с периферией,
- * затем переводим ее в режим работы с командами и проверяем
- * успешность перехода чтением JDEC ID (0x60), пробуем
- * стереть последний сектор флеши и затем в первую страницу последнего
- * сектора записываем тестовые данные, затем снова возвращаем режим QPI+XIP
- * и возвращаемся к первоначальной работе из флеш.
- * Все переходы сопровождаются миганием светодиодов.
- * Результат записи во флеш можно увидеть в отладчике по адресу 0х801FF000
- * после возвращения в режим работы с памятью
- */
- void SystemClock_Config();
- void GPIO_Init();
- void flash_write_page_qpi(void);
- int SPIFI_WaitIntrqTimeout(uint32_t timeout);
- uint32_t get_flash_usage_end(void);
- bool is_sector_free(uint32_t sector_address);
- uint8_t read_sreg_1(void);
- bool w25q_is_busy(uint32_t timeout);
- void write_enable(void);
- void w25q_sector_erase(uint32_t address);
- void page_program(unsigned int ByteAddress, uint8_t data[], int byte_count);
- bool write_to_last_sector(uint8_t *data);
- #define TIMEOUT 100000
- #define FLASH_TOTAL_SIZE (2 * 1024 * 1024)
- #define FLASH_BASE_ADDRESS 0x80000000
- #define SECTOR_SIZE 4096
- #define PAGE_SIZE 256
- volatile uint8_t jedec_id_qpi[3] = {0};
- extern uint32_t __DATA_IMAGE_END__;
- extern uint32_t __TEXT_END__;
- int main()
- {
- SystemClock_Config();
- GPIO_Init();
- flash_write_page_qpi();
- while (1)
- {
- // если мы попали сюда, значит мы успешно поработали с FLASH
- // из RAM и снова вернулись к работе программы из FLASH
- // и в отладчике теперь можно просмотреть результат записи
- HAL_GPIO_TogglePin(GPIO_0, GPIO_PIN_9 | GPIO_PIN_10);
- HAL_DelayMs(700);
- }
- }
- void SystemClock_Config(void)
- {
- PCC_InitTypeDef PCC_OscInit = {0};
- PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
- PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
- PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
- PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
- PCC_OscInit.AHBDivider = 0;
- PCC_OscInit.APBMDivider = 0;
- PCC_OscInit.APBPDivider = 0;
- PCC_OscInit.HSI32MCalibrationValue = 128;
- PCC_OscInit.LSI32KCalibrationValue = 8;
- PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
- PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
- HAL_PCC_Config(&PCC_OscInit);
- }
- void GPIO_Init()
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- __HAL_PCC_GPIO_0_CLK_ENABLE();
- GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
- GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_OUTPUT;
- GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
- HAL_GPIO_Init(GPIO_0, &GPIO_InitStruct);
- }
- void __attribute__((used, section(".ram_text"))) flash_write_page_qpi(void)
- {
- // мы сейчас с флеш точно работаем XIP + QPI, но перешли в ОЗУ и теперь нужно уйти из XIP,
- // т.е работали в режиме памяти, для этого надо перейти в режим периферии
- // сначала делаем сброс текущей команды работы в режиме памяти
- SPIFI_CONFIG->STAT = SPIFI_CONFIG_STAT_RESET_M;
- //выводим QPI из "без команд" в режим "с командами"
- const uint32_t cmd_chip_qpi_w_cmd =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(1) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_3ADDR) | /* нет кода операции, 3 адреса */
- SPIFI_CONFIG_CMD_OPCODE(0xEB);
- SPIFI_CONFIG->ADDR = 0;
- SPIFI_CONFIG->IDATA = 0;
- SPIFI_CONFIG->CMD = cmd_chip_qpi_w_cmd;
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // команда выполнена, выставлен IRQ, сбросим IRQ
- }
- else {
- asm("nop"); // таймаут, что-то пошло не так
- }
- // контрольная проверка принимает ли флеш команды или нет, для этого пробуем прочитать JDEC ID
- const uint32_t cmd_jedec_qpi =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(0) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE) |
- SPIFI_CONFIG_CMD_OPCODE(0x9F);
- SPIFI_CONFIG->ADDR = 0;
- SPIFI_CONFIG->IDATA = 0;
- SPIFI_CONFIG->CMD = cmd_jedec_qpi | SPIFI_CONFIG_CMD_DATALEN(3);
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // сбросим IRQ
- }
- else {
- asm("nop"); // таймаут, что-то пошло не так
- }
- for (int i = 0; i < 3; i++)
- jedec_id_qpi[i] = SPIFI_CONFIG->DATA8;
- // если успешно прочитали JDEC ID, то поморгаем вразнобой
- if(jedec_id_qpi[1] == 0x60){
- for(int i=0; i<16; i++)
- {
- GPIO_0->OUTPUT ^= 1<<9;
- for(int i=0; i<500000; i++)
- {
- asm("nop");
- }
- GPIO_0->OUTPUT ^= 1<<10;
- for(int i=0; i<500000; i++)
- {
- asm("nop");
- }
- }
- }
- for(int i=0; i<500000; i++){
- asm("nop");
- }
- //***** пробуем стереть и записать первую страницу последнего сектора ******
- uint8_t my_data[PAGE_SIZE];
- // формируем данные для записи
- for(int i=0; i<PAGE_SIZE; i++)
- my_data[i] = i;
- if (write_to_last_sector(my_data)) {
- // стирание и запись прошли успешно
- }
- //*************************************************************************
- //вернем назад QPI из режима "с командами" в режим "без команд"
- const uint32_t cmd_chip_qpi_wo_cmd =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(1) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE_3ADDR) | /* есть код операции, 3 адреса */
- SPIFI_CONFIG_CMD_OPCODE(0xEB);
- SPIFI_CONFIG->ADDR = 0;
- SPIFI_CONFIG->IDATA = 0x20;
- SPIFI_CONFIG->CMD = cmd_chip_qpi_wo_cmd;
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // команда выполнена, выставлен IRQ, сбросим IRQ
- }
- else {
- asm("nop"); // таймаут, что-то пошло не так
- }
- // а теперь вернем SPIFI в режим работы с памятью
- // настройки кэш не трогаем, они не изменились
- const uint32_t mcmd_chip_qpi_wo_cmd =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(1) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_3ADDR) | /* нет кода операции, 3 адреса */
- SPIFI_CONFIG_CMD_OPCODE(0xEB);
- SPIFI_CONFIG->ADDR = 0;
- SPIFI_CONFIG->IDATA = 0x20;
- SPIFI_CONFIG->MCMD = mcmd_chip_qpi_wo_cmd;
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // команда выполнена, выставлен IRQ, сбросим IRQ
- }
- else {
- asm("nop"); // таймаут, что-то пошло не так
- }
- // поморгали перед выходом из ОЗУ, если настройки правильные,
- // то после этого мы вернемся к работе программы из флеш
- GPIO_0->OUTPUT ^= 1<<9 | 1<<10;
- for(int i=0; i<16; i++)
- {
- GPIO_0->OUTPUT ^= 1<<9 | 1<<10;
- for(int i=0; i<500000; i++){
- asm("nop");
- }
- }
- }
- //*****************************************************************************
- // Получить конец используемой флеш-памяти
- __attribute__((used, section(".ram_text")))
- uint32_t get_flash_usage_end(void) {
- // Используем максимальный адрес между концом кода и концом данных
- uint32_t code_end = (uint32_t)&__TEXT_END__;
- uint32_t data_end = (uint32_t)&__DATA_IMAGE_END__;
- return (code_end > data_end) ? code_end : data_end;
- }
- //*****************************************************************************
- // Проверить, свободен ли сектор
- __attribute__((used, section(".ram_text")))
- bool is_sector_free(uint32_t sector_address) {
- // Сектор свободен, если он находится за пределами используемой памяти
- uint32_t usage_end = get_flash_usage_end();
- return (sector_address >= usage_end);
- }
- //*****************************************************************************
- __attribute__((used, section(".ram_text")))
- uint8_t read_sreg_1(void)
- {
- static uint8_t read_sreg = 0;
- const uint32_t cmd_read_sreg1 =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(0) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE) |
- SPIFI_CONFIG_CMD_OPCODE(0x05);
- SPIFI_CONFIG->CMD = cmd_read_sreg1 | SPIFI_CONFIG_CMD_DATALEN(1);
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) != 0){
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M; // сбросим IRQ
- }
- else {
- asm("nop"); // таймаут, что-то пошло не так
- return 0;
- }
- read_sreg = SPIFI_CONFIG->DATA8;
- return read_sreg;
- }
- //*****************************************************************************
- __attribute__((used, section(".ram_text")))
- bool w25q_is_busy(uint32_t timeout){
- while (timeout-- != 0)
- {
- if ((read_sreg_1() & 1) == 0)
- {
- asm("nop");
- return 0;
- }
- }
- return 1;
- }
- //*****************************************************************************
- __attribute__((used, section(".ram_text")))
- void write_enable(void)
- {
- const uint32_t cmd_write_enable =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(0) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE) |
- SPIFI_CONFIG_CMD_OPCODE(0x06);
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
- SPIFI_CONFIG->CMD = cmd_write_enable;
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) == 0)
- {
- return;
- }
- }
- //*****************************************************************************
- __attribute__((used, section(".ram_text")))
- void w25q_sector_erase(uint32_t address){
- write_enable();
- const uint32_t cmd_sector_erase_4k =
- SPIFI_DIRECTION_INPUT |
- SPIFI_CONFIG_CMD_INTLEN(0) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE_3ADDR) |
- SPIFI_CONFIG_CMD_OPCODE(0x20);
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
- SPIFI_CONFIG->ADDR = address;
- SPIFI_CONFIG->CMD = cmd_sector_erase_4k;
- if(SPIFI_WaitIntrqTimeout(TIMEOUT) == 0)
- {
- return;
- }
- }
- //*****************************************************************************
- __attribute__((used, section(".ram_text")))
- void page_program(unsigned int ByteAddress, uint8_t data[], int byte_count) {
- if(byte_count > 256)
- {
- return;
- }
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
- SPIFI_CONFIG->ADDR = ByteAddress;
- SPIFI_CONFIG->IDATA = 0x00;
- const uint32_t cmd_page_program =
- SPIFI_DIRECTION_OUTPUT |
- SPIFI_CONFIG_CMD_INTLEN(0) |
- SPIFI_CONFIG_CMD_FIELDFORM(SPIFI_FIELDFORM_ALL_PARALLEL) |
- SPIFI_CONFIG_CMD_FRAMEFORM(SPIFI_FRAMEFORM_OPCODE_3ADDR) |
- SPIFI_CONFIG_CMD_OPCODE(0x02);
- SPIFI_CONFIG->CMD = cmd_page_program | SPIFI_CONFIG_CMD_DATALEN(byte_count);
- for(int i = 0; i < byte_count; i++)
- {
- SPIFI_CONFIG->DATA8 = data[i];
- }
- SPIFI_CONFIG->STAT |= SPIFI_CONFIG_STAT_INTRQ_M;
- }
- //*****************************************************************************
- __attribute__((used, section(".ram_text")))
- bool write_to_last_sector(uint8_t *data){
- // Определяем адрес последнего сектора
- uint32_t last_sector_address = FLASH_BASE_ADDRESS + FLASH_TOTAL_SIZE - SECTOR_SIZE;
- // Проверяем, свободен ли сектор
- if (!is_sector_free(last_sector_address)) {
- // Сектор занят - нельзя использовать
- return 0;
- }
- // Стираем сектор (это необходимо перед записью)
- w25q_sector_erase(last_sector_address);
- if(w25q_is_busy(TIMEOUT) == 1){
- return 0;
- }
- write_enable();
- page_program(last_sector_address, data, PAGE_SIZE);
- if(w25q_is_busy(TIMEOUT) == 1){
- return 0;
- }
- return 1;
- }
- //*****************************************************************************
- int __attribute__((used, section(".ram_text"))) SPIFI_WaitIntrqTimeout(uint32_t timeout)
- {
- while (timeout-- > 0)
- {
- if((SPIFI_CONFIG->STAT & SPIFI_CONFIG_STAT_INTRQ_M) != 0)
- {
- return 1;
- }
- }
- return 0;
- }
- //*****************************************************************************
Advertisement
Add Comment
Please, Sign In to add comment