Jump to content

    
Sign in to follow this  
evgen.05

STM32H745 custom flashloader

Recommended Posts

решил прикрутить QSPI флешку W25Q64 к STM32H745. Драйвер написал. Флешка стирается, пишется, читается. Данные, записанные на флешку, успешно верифицируются, ошибок нет. Но почему-то ничего не работает, когда пытаюсь написать свой флешлодырь.
Линкер

Скрытый текст

/*
*****************************************************************************
**  File        : linker.ld
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used.
**
**  Target      : STMicroelectronics STM32
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Init)

/* Generate 2 segment for Loader code and device info */
PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; }

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200 ;      /* required amount of heap  */
_Min_Stack_Size = 0x400 ; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
  RAM_PROG (xrw) : ORIGIN = 0x24000004, LENGTH = 256K-4 /* 0x20000004 for Non-H7 */
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
 
  .isr_vector :
  {
      . = . + 0x1FC;
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >RAM :Loader
 

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >RAM :Loader

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >RAM :Loader
 
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >RAM :Loader
 
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >RAM :Loader

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM :Loader

 
  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM :Loader

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >RAM :Loader
 
    .Dev_info :
  {
    KEEP(*Dev_Inf.o ( .rodata* ))
  } :SgInfo
 
 
  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >RAM :Loader
 
 
  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM :Loader



  .ARM.attributes 0 : { *(.ARM.attributes) }
}

 

 

loader.src

Скрытый текст

 


#include "quadspi.h"
#include "main.h"
#include "gpio.h"

#define LOADER_OK	0x1
#define LOADER_FAIL	0x0

/**
 * @brief  System initialization.
 * @param  None
 * @retval  LOADER_OK = 1	: Operation succeeded
 * @retval  LOADER_FAIL = 0	: Operation failed
 */
int Init(void) {

	*(uint32_t*)0xE000EDF0=0xA05F0000; //enable interrupts in debug

	SystemInit();

/* ADAPTATION TO THE DEVICE
 *
 * change VTOR setting for H7 device
 * SCB->VTOR = 0x24000000 | 0x200;
 *
 * change VTOR setting for other devices
 * SCB->VTOR = 0x20000000 | 0x200;
 *
 * */

	SCB->VTOR = 0x24000000 | 0x200;

	HAL_Init();

    SystemClock_Config();

    __HAL_RCC_HSEM_CLK_ENABLE();

    MX_GPIO_Init();
	
	__HAL_RCC_QSPI_FORCE_RESET();  //completely reset peripheral
    __HAL_RCC_QSPI_RELEASE_RESET();

    HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);


	if (CSP_QUADSPI_Init() != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}


	if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}

		HAL_SuspendTick();
		return LOADER_OK;
}

/**
 * @brief   Program memory.
 * @param   Address: page address
 * @param   Size   : size of data
 * @param   buffer : pointer to data buffer
 * @retval  LOADER_OK = 1		: Operation succeeded
 * @retval  LOADER_FAIL = 0	: Operation failed
 */
int Write(uint32_t Address, uint32_t Size, uint8_t* buffer) {

	HAL_ResumeTick();


	if(HAL_QSPI_Abort(&hqspi) != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}


	if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)),Size) != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}

	HAL_SuspendTick();
	return LOADER_OK;
}

/**
 * @brief   Sector erase.
 * @param   EraseStartAddress :  erase start address
 * @param   EraseEndAddress   :  erase end address
 * @retval  LOADER_OK = 1		: Operation succeeded
 * @retval  LOADER_FAIL = 0	: Operation failed
 */
int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {

	HAL_ResumeTick();

	if(HAL_QSPI_Abort(&hqspi) != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}


	if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}

	HAL_SuspendTick();
	return LOADER_OK;
}

/**
 * Description :
 * Mass erase of external flash area
 * Optional command - delete in case usage of mass erase is not planed
 * Inputs    :
 *      none
 * outputs   :
 *     none
 * Note: Optional for all types of device
 */
int MassErase(void) {

	HAL_ResumeTick();


	if(HAL_QSPI_Abort(&hqspi) != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}


	if (CSP_QSPI_Erase_Chip() != HAL_OK)
	{
		 HAL_SuspendTick();
		return LOADER_FAIL;
	}

	HAL_SuspendTick();
	return LOADER_OK;
}

/**
 * Description :
 * Calculates checksum value of the memory zone
 * Inputs    :
 *      StartAddress  : Flash start address
 *      Size          : Size (in WORD)
 *      InitVal       : Initial CRC value
 * outputs   :
 *     R0             : Checksum value
 * Note: Optional for all types of device
 */
uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) {
	uint8_t missalignementAddress = StartAddress % 4;
	uint8_t missalignementSize = Size;
	int cnt;
	uint32_t Val;

	StartAddress -= StartAddress % 4;
	Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4);

	for (cnt = 0; cnt < Size; cnt += 4) {
		Val = *(uint32_t*) StartAddress;
		if (missalignementAddress) {
			switch (missalignementAddress) {
			case 1:
				InitVal += (uint8_t) (Val >> 8 & 0xff);
				InitVal += (uint8_t) (Val >> 16 & 0xff);
				InitVal += (uint8_t) (Val >> 24 & 0xff);
				missalignementAddress -= 1;
				break;
			case 2:
				InitVal += (uint8_t) (Val >> 16 & 0xff);
				InitVal += (uint8_t) (Val >> 24 & 0xff);
				missalignementAddress -= 2;
				break;
			case 3:
				InitVal += (uint8_t) (Val >> 24 & 0xff);
				missalignementAddress -= 3;
				break;
			}
		} else if ((Size - missalignementSize) % 4 && (Size - cnt) <= 4) {
			switch (Size - missalignementSize) {
			case 1:
				InitVal += (uint8_t) Val;
				InitVal += (uint8_t) (Val >> 8 & 0xff);
				InitVal += (uint8_t) (Val >> 16 & 0xff);
				missalignementSize -= 1;
				break;
			case 2:
				InitVal += (uint8_t) Val;
				InitVal += (uint8_t) (Val >> 8 & 0xff);
				missalignementSize -= 2;
				break;
			case 3:
				InitVal += (uint8_t) Val;
				missalignementSize -= 3;
				break;
			}
		} else {
			InitVal += (uint8_t) Val;
			InitVal += (uint8_t) (Val >> 8 & 0xff);
			InitVal += (uint8_t) (Val >> 16 & 0xff);
			InitVal += (uint8_t) (Val >> 24 & 0xff);
		}
		StartAddress += 4;
	}

	return (InitVal);
}

/**
 * Description :
 * Verify flash memory with RAM buffer and calculates checksum value of
 * the programmed memory
 * Inputs    :
 *      FlashAddr     : Flash address
 *      RAMBufferAddr : RAM buffer address
 *      Size          : Size (in WORD)
 *      InitVal       : Initial CRC value
 * outputs   :
 *     R0             : Operation failed (address of failure)
 *     R1             : Checksum value
 * Note: Optional for all types of device
 */
uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size,uint32_t missalignement){

	HAL_ResumeTick();
	uint32_t VerifiedData = 0, InitVal = 0;
	uint64_t checksum;
	Size *= 4;

	if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK)
	{
		HAL_SuspendTick();
		return LOADER_FAIL;
	}

	checksum = CheckSum((uint32_t) MemoryAddr + (missalignement & 0xf),
			Size - ((missalignement >> 16) & 0xF), InitVal);
	while (Size > VerifiedData) {
		if (*(uint8_t*) MemoryAddr++
				!= *((uint8_t*) RAMBufferAddr + VerifiedData)){
			HAL_SuspendTick();
			return ((checksum << 32) + (MemoryAddr + VerifiedData));
		}
		VerifiedData++;
	}

	HAL_SuspendTick();
	return (checksum << 32);
} 

 

Делал по этой инструкции https://drive.google.com/drive/folders/1KiaqXgiubk81EvevofK-y3LxrCl9NHfi

Пытался отладить все это дело. Вываливается в ошибку уже на CSP_QUADSPI_Init() этой функции. В ней первым делом идет инициализация интерфейса QSPI, успешно все проходит, а затем шлется команда Software Reset на микросхему памяти. Точнее должна быть послана такая команда. Но в порт вообще не пишется ничего. Ни одна нога не дергается. Не происходит вообще ничего и по таймауту программа ожидаемо вываливается в ошибку. Насколько я понимаю, дело в линкере, но мозгов не хватает понять что и как. Может у кого идеи есть куда копнуть?

Edited by evgen.05

Share this post


Link to post
Share on other sites

Все. Победил сам. Бутлодырь прилагаю, может кому понадобится.
Использованы следующие пины:

  1. //**********************
  2. // QSPI W25Q64
  3. //**********************
  4. // PD11 IO0
  5. // PD12 IO1
  6. // PE2  IO2
  7. // PD13 IO3
  8. //
  9. // PB2  CLK
  10. // PB6  CS
  11. //**********************

QSPI_W25Q64_Nucleo-144_STM32H745.stldr

Share this post


Link to post
Share on other sites
1 hour ago, evgen.05 said:

Все. Победил сам. Бутлодырь прилагаю, может кому понадобится.
Использованы следующие пины:

  1. //**********************
  2. // QSPI W25Q64
  3. //**********************
  4. // PD11 IO0
  5. // PD12 IO1
  6. // PE2  IO2
  7. // PD13 IO3
  8. //
  9. // PB2  CLK
  10. // PB6  CS
  11. //**********************

QSPI_W25Q64_Nucleo-144_STM32H745.stldr 2.39 MB · 0 downloads

Вместе с исходниками на github !

Share this post


Link to post
Share on other sites
36 минут назад, x893 сказал:

Вместе с исходниками на github !

В исходниках абсолютно ничего интересного. В первом сообщении есть все, что нужно. Я лишь изменил режим работы памяти на полноценный QSPI, где команда и адрес передаются на микросхему памяти по четырем проводам, а не по одному, как в оригинале, ну и добавил полноценное отслеживание бита BUSY в памяти. Без него запись происходила с ошибками. Стабильная работа получилась у меня на 40МГц CLK.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this