Продолжая тему программирования контроллера STM32F4 и также работу с последовательной FLASH-памятью серии W25Q, мы попытаемся с помощью программы для ПК прочитать данные из памяти микросхемы. Причём прочитаем мы все данные полностью, и, мало того, попробуем их сохранить в файл. Это позволит нам полностью сохранить нашу прошивку, как говорят, сделать дамп FLASH-памяти, для дальнейшего её использования.
Программу также можно будет скачать по ссылке внизу страницы.
Схема урока не изменилась, осталась такая же, как и в прошлом уроке
И проект мы за основу также возьмём из прошлого урока с именем SPI_25Q32_INFO_TO_PC и присвоим ему новое имя SPI_25Q32_READ_TO_PC.
Откроем наш проект в Cube MX и прибавим скорость для UART, иначе мы будем очень долго считывать информацию даже из 32-килобитной микросхемы
Сгенерируем проект, откроем его в Keil, подключим файл w25q_spi.c, настроим программатор на автоперезагрузку, а также отключим оптимизацию.
Если мы теперь соберём прошьём проект, то, когда будем пробовать нашу программу в действии, то в программе для ПК, мы должны будем изменить значение битрейта
Прочитаем служебную информацию
Всё у нас работает.
Возвращаемся к нашему проекту.
Первым делом из файла w25q_spi.c в файл w25q_spi.h перенесём объявление структуры w25_info_t, иначе её тип не виден в других файлах. Объявление переменной данного типа не переносим, только самой структуры
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <string.h> //------------------------------------------------------------- typedef struct { uint16_t PageSize; uint32_t PageCount; uint32_t SectorSize; uint32_t SectorCount; uint32_t BlockSize; uint32_t BlockCount; uint32_t NumKB; uint8_t SR1; uint8_t SR2; uint8_t SR3; uint8_t high_cap; }w25_info_t; //------------------------------------------------------------- |
В файле main.c подключим переменную
1 2 |
/* USER CODE BEGIN PV */ extern w25_info_t w25_info; |
В бесконечном цикле в функции main() добавим комментарий, чтобы было понятно, какую мы ждём команду
1 2 3 |
HAL_UART_Receive(&huart1,(uint8_t*)dt1,1,0x10); //command Info if(dt1[0] == 33) |
Для индикации различных команд мы будем использовать разные светодиоды, поэтому погасим красный светодиод
1 2 |
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_RESET); |
Добавим также комментарий, сообщающий о том что далее мы передаём длину пакета
1 2 3 |
dt1[0] = 0x05; //packet length *(unsigned int*)(dt1+1) = strlen((char*)rx_buf); |
После длины пакета мы будем передавать также общее количество страниц памяти, а также размер страницы
1 2 3 4 5 |
HAL_UART_Transmit(&huart1,(uint8_t*)dt1,5,0x1000); //Count and size Pages *(unsigned int*)dt1 = w25_info.PageCount; *(unsigned int*)(dt1+4) = w25_info.PageSize; HAL_UART_Transmit(&huart1,(uint8_t*)dt1,8,0x1000); |
Выйдя из тела условия, добавим другое условие, в котором мы будем ждать от компьютера команду на чтение уже не служебной информации, а информации непосредственно из памяти микросхемы
1 2 3 4 5 6 |
HAL_UART_Transmit(&huart1,rx_buf,strlen((char*)rx_buf),0x1000); } //command Read else if(dt1[0] == 34) { } |
Если мы дождались именно такой команды, то зажжём красный светодиод, а зелёный погасим
1 2 3 4 |
else if(dt1[0] == 34) { HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); |
Добавим цикл, в котором прочитаем в буфер содержимое очередной страницы
1 2 3 4 5 |
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); for(unsigned int num_page = 0; num_page < w25_info.PageCount; num_page++) { W25_Read_Page(rx_buf, num_page, 0, w25_info.PageSize); } |
Аналогично первому условию начнём готовить данные.
Оправим компьютеру команду, которая объяснит ему, что от нас идут именно полезные данные и их размер, равный размеру одной страницы
1 2 3 4 5 |
W25_Read_Page(rx_buf, num_page, 0, w25_info.PageSize); //06 - read dt1[0] = 0x06; *(unsigned int*)(dt1+1) = w25_info.PageSize; HAL_UART_Transmit(&huart1,(uint8_t*)dt1,5,0x1000); |
Далее передадим содержимое нашей страницы
Передачу разделим по 100 байтов, так компьютер принимает лучше, так почему-то программа не совсем корректно работает с большими порциями
1 2 3 4 5 6 |
HAL_UART_Transmit(&huart1,(uint8_t*)dt1,5,0x1000); for(unsigned int i = 0; i < w25_info.PageSize / 100; i++) { HAL_UART_Transmit(&huart1,rx_buf+i*100,100,0x1000); } HAL_UART_Transmit(&huart1,rx_buf + w25_info.PageSize / 100,w25_info.PageSize % 100,0x1000); |
Размер страницы и количество страниц мы уже не передаём, компьютер их уже знает, так как он получил это по первой команде.
В принципе, наша программа готова.
Проверим её работу. Соберём код, прошьём контроллер, запустим программу на компьютере, считаем служебную информацию, после чего кнопка чего кнопка чтения памяти станет активной. Попытаемся прочитать содержимое памяти микросхемы
Когда процесс считывания закончится, мы увидим содержимое памяти в шестнадцатеричном виде
Мы видим, что стала активной кнопка записи в файл. Попробуем воспользоваться ей и сохранить наш дамп для чего назовём наш файл и сохраним в нужное нам место на компьютере
Мы видим, что файл наш сохранился
Откроем его и посмотрим
Содержимое похоже на оригинальное. Вообще я сравнивал получившийся файл с оригинальным, который я записывал в микросхему с помощью программатора — всё сходится, файлы одинаковы.
Итак, на данном уроке нам удалось считать всю информацию из микросхемы, передать её на компьютер, после чего сохранить в файл.
Всем спасибо за внимание!
Предыдущий урок Программирование МК STM32 Следующий урок
Программа для работы с микросхемой
Отладочную плату можно приобрести здесь STM32F429I-DISCO
Микросхему FLASH-памяти W25Q32FVSSIG SOP8 (10 штук) можно приобрести здесь W25Q32FVSSIG
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добавить комментарий