Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5012c9a0f0 | |||
| 85b74eb004 | |||
| c4e8171e25 | |||
| 32608935ec | |||
| a10a08d898 | |||
|
|
aff7a7ebce | ||
| 2452db9096 | |||
| 95e86f9ead | |||
| eb7ef97139 |
@ -14,3 +14,4 @@ platform = MIK32
|
|||||||
board = mik32v2
|
board = mik32v2
|
||||||
framework = framework-mik32v2-sdk
|
framework = framework-mik32v2-sdk
|
||||||
board_debug.ldscript = eeprom
|
board_debug.ldscript = eeprom
|
||||||
|
board_upload.maximum_size=5000
|
||||||
|
|||||||
103
src/bootloader.c
103
src/bootloader.c
@ -11,6 +11,11 @@
|
|||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
|
// версия начального загрузчика
|
||||||
|
#define MAJOR_VER 0
|
||||||
|
#define MINOR_VER 2
|
||||||
|
#define BUGFIX_VER 0
|
||||||
|
|
||||||
#define JALR_TO_SPIFI() \
|
#define JALR_TO_SPIFI() \
|
||||||
asm volatile( "la ra, 0x80000000\n\t" \
|
asm volatile( "la ra, 0x80000000\n\t" \
|
||||||
"jalr ra" \
|
"jalr ra" \
|
||||||
@ -29,6 +34,7 @@ typedef enum
|
|||||||
{
|
{
|
||||||
PACKAGE_SIZE = 0x30, /* Команда размера пакета */
|
PACKAGE_SIZE = 0x30, /* Команда размера пакета */
|
||||||
SEND_PACKAGE = 0x60, /* Команда отправить пакет */
|
SEND_PACKAGE = 0x60, /* Команда отправить пакет */
|
||||||
|
VERSION = 0x90, /* Команда получения версии начального загрузчика */
|
||||||
FULL_ERASE = 0xBADC0FEE /* Команда стирания spifi */
|
FULL_ERASE = 0xBADC0FEE /* Команда стирания spifi */
|
||||||
} BotloaderComand;
|
} BotloaderComand;
|
||||||
|
|
||||||
@ -41,7 +47,8 @@ typedef enum
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
ERROR_NONE = 0,
|
ERROR_NONE = 0,
|
||||||
ERROR_TIMEOUT = 1, // Время ожидания истекло
|
ERROR_TIMEOUT = 1, // Время ожидания истекло
|
||||||
|
ERROR_CRC, // Ошибка при получении строки hex от ПК или при записи страницы данных на flash
|
||||||
} Bootloader_error;
|
} Bootloader_error;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -101,7 +108,7 @@ void Bootloader_UART_Deinit()
|
|||||||
// Отключение притяжки на линии rx
|
// Отключение притяжки на линии rx
|
||||||
PAD_CONFIG->PORT_0_PUPD &= ~(0b01 << (5 << 1));
|
PAD_CONFIG->PORT_0_PUPD &= ~(0b01 << (5 << 1));
|
||||||
|
|
||||||
PM->CLK_APB_P_SET &= !PM_CLOCK_APB_P_UART_0_M; // Выключение тактирования UART0
|
PM->CLK_APB_P_CLEAR = PM_CLOCK_APB_P_UART_0_M; // Выключение тактирования UART0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Отправить байт */
|
/* Отправить байт */
|
||||||
@ -142,6 +149,14 @@ void Bootloader_ErrorHandler()
|
|||||||
|
|
||||||
go_to_spifi(); // переход в основную программу, если в течение TIMEOUT_VALUE нет принятых данных
|
go_to_spifi(); // переход в основную программу, если в течение TIMEOUT_VALUE нет принятых данных
|
||||||
break;
|
break;
|
||||||
|
case ERROR_CRC:
|
||||||
|
// отправить nack и перейти в основную программу, если приняли некорректные данные
|
||||||
|
Bootloader_UART_WriteByte(NACK);
|
||||||
|
|
||||||
|
if (UART_0->FLAGS & UART_FLAGS_ORE_M)
|
||||||
|
UART_0->FLAGS |= UART_FLAGS_ORE_M;
|
||||||
|
go_to_spifi();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
hBootloader.error = ERROR_NONE;
|
hBootloader.error = ERROR_NONE;
|
||||||
@ -168,8 +183,8 @@ uint8_t erase_chip(SPIFI_HandleTypeDef *spifi)
|
|||||||
|
|
||||||
// разметка строки в хекс-файле
|
// разметка строки в хекс-файле
|
||||||
#define BYTE_COUNT_POS 0 // индекс счетчика байт данных
|
#define BYTE_COUNT_POS 0 // индекс счетчика байт данных
|
||||||
#define ADDRES_POS 1 // индекс адреса
|
#define ADDRESS_POS 1 // индекс адреса
|
||||||
#define ADDRES_QTY 2 // количество байт адреса
|
#define ADDRESS_QTY 2 // количество байт адреса
|
||||||
#define RECORD_TYPE_POS 3 // индекс типа записи
|
#define RECORD_TYPE_POS 3 // индекс типа записи
|
||||||
#define DATA_POS 4 // индекс начала данных в команде
|
#define DATA_POS 4 // индекс начала данных в команде
|
||||||
|
|
||||||
@ -183,6 +198,22 @@ uint32_t rel_addr = 0; // адрес от начала области spifi, п
|
|||||||
#define TAIL_SIZE 15 // если попадутся строки хекса, в которых не 16 байт, то мы рискуем записать данные уарта мимо буфера package_data. а если больше 16 байт, то это проблема завтрашнего дня
|
#define TAIL_SIZE 15 // если попадутся строки хекса, в которых не 16 байт, то мы рискуем записать данные уарта мимо буфера package_data. а если больше 16 байт, то это проблема завтрашнего дня
|
||||||
uint8_t page_data[MAX_PACKAGE_SIZE + TAIL_SIZE] = {0}; // сюда собираем распарсенные данные из хекса
|
uint8_t page_data[MAX_PACKAGE_SIZE + TAIL_SIZE] = {0}; // сюда собираем распарсенные данные из хекса
|
||||||
uint16_t page_fill_size = 0; // счетчик, сколько заполнно в page_data. когда page_data заполнена до конца - будем записывать в spifi
|
uint16_t page_fill_size = 0; // счетчик, сколько заполнно в page_data. когда page_data заполнена до конца - будем записывать в spifi
|
||||||
|
uint8_t read_data[MAX_PACKAGE_SIZE] = {0};
|
||||||
|
|
||||||
|
bool page_data_is_written(void)
|
||||||
|
{
|
||||||
|
// читаем ту же страницу в другой буфер
|
||||||
|
memset(read_data, 0xFF, MAX_PACKAGE_SIZE);
|
||||||
|
HAL_SPIFI_W25_ReadData(&spifi, (uint32_t)hBootloader.address, MAX_PACKAGE_SIZE, read_data);
|
||||||
|
// побайтово сравниваем содержимое двух буферов
|
||||||
|
for (uint16_t i = 0; i < MAX_PACKAGE_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (read_data[i] != page_data[i])
|
||||||
|
// если не сходится хоть один байт, прерываем проверку
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void mem_write()
|
void mem_write()
|
||||||
{
|
{
|
||||||
@ -193,18 +224,27 @@ void mem_write()
|
|||||||
|
|
||||||
// записываем страницу в 256 байт в spifi
|
// записываем страницу в 256 байт в spifi
|
||||||
HAL_SPIFI_W25_PageProgram(&spifi, (uint32_t)hBootloader.address, MAX_PACKAGE_SIZE, page_data);
|
HAL_SPIFI_W25_PageProgram(&spifi, (uint32_t)hBootloader.address, MAX_PACKAGE_SIZE, page_data);
|
||||||
|
|
||||||
|
// проверить, записалось ли действительно содержимое буфера
|
||||||
|
if (!page_data_is_written())
|
||||||
|
{
|
||||||
|
// если не записалось, выставим ошибку по crc и выходим
|
||||||
|
hBootloader.error = ERROR_CRC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// увеличиваем адреса, по которым писать и стирать
|
// увеличиваем адреса, по которым писать и стирать
|
||||||
hBootloader.address += MAX_PACKAGE_SIZE;
|
hBootloader.address += MAX_PACKAGE_SIZE;
|
||||||
// обнуляем часть буфера, которая была записана в память и уменьшаем счетчик заполнения буфера на столько, сколько было записано
|
// очищаем часть буфера, которая была записана в память и уменьшаем счетчик заполнения буфера на столько, сколько было записано
|
||||||
if (page_fill_size <= MAX_PACKAGE_SIZE)
|
if (page_fill_size <= MAX_PACKAGE_SIZE)
|
||||||
page_fill_size = 0;
|
page_fill_size = 0;
|
||||||
else
|
else
|
||||||
page_fill_size -= MAX_PACKAGE_SIZE;
|
page_fill_size -= MAX_PACKAGE_SIZE;
|
||||||
memset(&page_data[0], 0, MAX_PACKAGE_SIZE);
|
memset(&page_data[0], 0xFF, MAX_PACKAGE_SIZE);
|
||||||
// хвост копируем в начало буфера, чтобы записать его в следующий раз
|
// хвост копируем в начало буфера, чтобы записать его в следующий раз
|
||||||
memcpy(&page_data[0], &page_data[MAX_PACKAGE_SIZE], TAIL_SIZE);
|
memcpy(&page_data[0], &page_data[MAX_PACKAGE_SIZE], TAIL_SIZE);
|
||||||
// а сам хвост обнуляем
|
// а сам хвост очищаем
|
||||||
memset(&page_data[MAX_PACKAGE_SIZE], 0, TAIL_SIZE);
|
memset(&page_data[MAX_PACKAGE_SIZE], 0xFF, TAIL_SIZE);
|
||||||
}
|
}
|
||||||
void Bootloader_parseHexAndLoadInMemory(uint8_t rx_data[])
|
void Bootloader_parseHexAndLoadInMemory(uint8_t rx_data[])
|
||||||
{
|
{
|
||||||
@ -226,7 +266,7 @@ void Bootloader_parseHexAndLoadInMemory(uint8_t rx_data[])
|
|||||||
memcpy(&page_data[page_fill_size], &rx_data[DATA_POS], rx_data[BYTE_COUNT_POS]);
|
memcpy(&page_data[page_fill_size], &rx_data[DATA_POS], rx_data[BYTE_COUNT_POS]);
|
||||||
// указываем, на сколько заполнился буфер
|
// указываем, на сколько заполнился буфер
|
||||||
page_fill_size += rx_data[BYTE_COUNT_POS];
|
page_fill_size += rx_data[BYTE_COUNT_POS];
|
||||||
// если пора записывать целую страницу - пишемм
|
// если пора записывать целую страницу - пишем
|
||||||
if (page_fill_size >= 256)
|
if (page_fill_size >= 256)
|
||||||
mem_write();
|
mem_write();
|
||||||
break;
|
break;
|
||||||
@ -235,7 +275,12 @@ void Bootloader_parseHexAndLoadInMemory(uint8_t rx_data[])
|
|||||||
Bootloader_UART_WriteByte(ACK);
|
Bootloader_UART_WriteByte(ACK);
|
||||||
// если есть недозаполненная страница, записываем ее как есть
|
// если есть недозаполненная страница, записываем ее как есть
|
||||||
if (page_fill_size != 0)
|
if (page_fill_size != 0)
|
||||||
|
{
|
||||||
mem_write();
|
mem_write();
|
||||||
|
// если при записи остатков возникли ошибки, здесь в основную программу не будем переходить
|
||||||
|
if (hBootloader.error)
|
||||||
|
return;
|
||||||
|
}
|
||||||
// и идем в записанную программу
|
// и идем в записанную программу
|
||||||
go_to_spifi();
|
go_to_spifi();
|
||||||
break;
|
break;
|
||||||
@ -245,29 +290,38 @@ void Bootloader_parseHexAndLoadInMemory(uint8_t rx_data[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t uart_data[MAX_PACKAGE_SIZE] = {0}; // Массив данных из полученного пакета
|
uint8_t uart_data[MAX_PACKAGE_SIZE] = {0}; // Массив данных из полученного пакета
|
||||||
|
uint32_t crc_acc = 0;
|
||||||
|
uint8_t crc = 0;
|
||||||
void Bootloader_UART_ReadPackage()
|
void Bootloader_UART_ReadPackage()
|
||||||
{
|
{
|
||||||
|
crc_acc = 0;
|
||||||
for (uint32_t counter = 0; counter < hBootloader.size_package; counter++)
|
for (uint32_t counter = 0; counter < hBootloader.size_package; counter++)
|
||||||
{
|
{
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
while ((!(UART_0->FLAGS & UART_FLAGS_RXNE_M)) && (timeout != TIMEOUT_VALUE)) // Ожидание байта пакета
|
while ((!(UART_0->FLAGS & UART_FLAGS_RXNE_M)) && (timeout != TIMEOUT_VALUE)) // Ожидание байта пакета
|
||||||
{
|
|
||||||
timeout++;
|
timeout++;
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout == TIMEOUT_VALUE)
|
if (timeout == TIMEOUT_VALUE)
|
||||||
{
|
{
|
||||||
hBootloader.error = ERROR_TIMEOUT;
|
hBootloader.error = ERROR_TIMEOUT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_data[counter] = UART_0->RXDATA;
|
uart_data[counter] = UART_0->RXDATA;
|
||||||
|
|
||||||
|
// контрольная сумма идет последним байтом в пакете. Суммируем всё, кроме нее
|
||||||
|
if (counter < (hBootloader.size_package-1))
|
||||||
|
crc_acc += uart_data[counter];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// посчитать контрольную сумму и сравнить
|
||||||
|
crc = (256 - crc_acc % 256) % 256;
|
||||||
|
if (crc != uart_data[counter])
|
||||||
|
hBootloader.error = ERROR_CRC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hBootloader.error)
|
if (hBootloader.error == ERROR_NONE)
|
||||||
{
|
|
||||||
Bootloader_parseHexAndLoadInMemory(uart_data);
|
Bootloader_parseHexAndLoadInMemory(uart_data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t eraseChipBufferIndex = 0; // Индекс для накопления команды erase chip
|
uint8_t eraseChipBufferIndex = 0; // Индекс для накопления команды erase chip
|
||||||
@ -287,6 +341,15 @@ void Bootloader_Commands()
|
|||||||
{
|
{
|
||||||
switch (hBootloader.command)
|
switch (hBootloader.command)
|
||||||
{
|
{
|
||||||
|
case VERSION:
|
||||||
|
validCommandsTimeout = 0; // Сброс таймаута валидных команд
|
||||||
|
eraseChipBufferIndex = 0;
|
||||||
|
Bootloader_UART_WriteByte(ACK); // Подтвердить команду
|
||||||
|
// отправить все составляющие версии загрузчика
|
||||||
|
Bootloader_UART_WriteByte((uint16_t)MAJOR_VER);
|
||||||
|
Bootloader_UART_WriteByte((uint16_t)MINOR_VER);
|
||||||
|
Bootloader_UART_WriteByte((uint16_t)BUGFIX_VER);
|
||||||
|
break;
|
||||||
case PACKAGE_SIZE:
|
case PACKAGE_SIZE:
|
||||||
validCommandsTimeout = 0; // Сброс таймаута валидных команд
|
validCommandsTimeout = 0; // Сброс таймаута валидных команд
|
||||||
eraseChipBufferIndex = 0;
|
eraseChipBufferIndex = 0;
|
||||||
@ -404,12 +467,12 @@ void SPIFI_Init()
|
|||||||
HAL_SPIFI_Reset(&spifi);
|
HAL_SPIFI_Reset(&spifi);
|
||||||
|
|
||||||
/* В Winbond для выставления QE используется команда 0x01 в 1-м бите 2го статус регистра. */
|
/* В Winbond для выставления QE используется команда 0x01 в 1-м бите 2го статус регистра. */
|
||||||
|
uint8_t sreg1 = HAL_SPIFI_W25_ReadSREG(&spifi, W25_SREG1);
|
||||||
|
if (sreg1 > 0x03) sreg1 = 0; // снятие защиты от записи (protection bits)
|
||||||
uint8_t sreg2 = HAL_SPIFI_W25_ReadSREG(&spifi, W25_SREG2);
|
uint8_t sreg2 = HAL_SPIFI_W25_ReadSREG(&spifi, W25_SREG2);
|
||||||
if (!(sreg2 & (1 << 1)))
|
if (!(sreg2 & 0x02)) sreg2 |= 0x02; // установка бита QE (quad enable)
|
||||||
{
|
if (sreg2 & 0x40) sreg2 &= ~0x40; // сброс бита CMP. Если вдруг он выставился по какой-то причине, часть или вся память можеть быть заблокирована для записи
|
||||||
uint8_t sreg1 = HAL_SPIFI_W25_ReadSREG(&spifi, W25_SREG1);
|
HAL_SPIFI_W25_WriteSREG(&spifi, sreg1, sreg2);
|
||||||
HAL_SPIFI_W25_WriteSREG(&spifi, sreg1, sreg2 | (1 << 1)); // ? HAL_SPIFI_W25_QuadEnable(&spifi);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CHIP_MODE == 1
|
#if CHIP_MODE == 1
|
||||||
/* Переключение флеш-памяти в режим QPI, когда весь обмен четырёхпроводной */
|
/* Переключение флеш-памяти в режим QPI, когда весь обмен четырёхпроводной */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user