cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G474RET ADC DMA error after changing SCB->VTOR

JNg
Associate II

I have added a bootloader to my code with 0x4000 size. I added SCB->VTOR = 0x8004000 before memory jump from bootloader to app code and I also added SCB->VTOR = 0x8004000 at the first line in the app code main.c . The memory jump works well. My freeRTOs threads, UART and USB are working. But I start having ADC DMA error.

If I remove SCB->VTOR = 0x8004000 and bootloader to run my app code by itself. The ADC DMA has no error.

Is there any instruction I need to do beside setting SCB->VTOR value to make DMA work?

Jump code in bootloader:

void (*SysMemBootJump)(void);

volatile uint32_t addr = 0x8004000;

uint8_t i;

__disable_irq();

/* Clear Interrupt Enable Register & Interrupt Pending Register */

for (i=0;i<4;i++){

NVIC->ICER[i]=0xFFFFFFFF;

NVIC->ICPR[i]=0xFFFFFFFF;

}

    HAL_RCC_DeInit();

   HAL_DeInit();

SysTick->CTRL = 0;

SysTick->LOAD = 0;

SysTick->VAL = 0;

__enable_irq();

SCB->VTOR = addr;

SysMemBootJump = (void (*)(void)) (*((uint32_t *) (addr + 4)));

__set_MSP(*(uint32_t *) addr);

SysMemBootJump();

4 REPLIES 4

> But I start having ADC DMA error.

What exactly does this mean?

JW

JNg
Associate II

Below pictures are the ADC config in CubeMX. It is a Ranks 3 setup for 3 ADC channels. The error happens at the ADC_Enable() in the HAL_ADC_Start_DMA() function call. It always timeout in the ADC_Enable() while loop and return HAL_ERROR. The HAL_ADC_Start_DMA() is called in freeRTOS threads every half second. This function used to work without SCB->VTOR = 0x8004000 and bootloader.

HAL_StatusTypeDef ADC_Enable(ADC_HandleTypeDef *hadc)

{

 uint32_t tickstart;

 /* ADC enable and wait for ADC ready (in case of ADC is disabled or     */

 /* enabling phase not yet completed: flag ADC ready not yet set).      */

 /* Timeout implemented to not be stuck if ADC cannot be enabled (possible  */

 /* causes: ADC clock not running, ...).                   */

 if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)

 {

  /* Check if conditions to enable the ADC are fulfilled */

  if ((hadc->Instance->CR & (ADC_CR_ADCAL | ADC_CR_JADSTP | ADC_CR_ADSTP | ADC_CR_JADSTART | ADC_CR_ADSTART | ADC_CR_ADDIS | ADC_CR_ADEN)) != 0UL)

  {

   /* Update ADC state machine to error */

   SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);

   /* Set ADC error code to ADC peripheral internal error */

   SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);

   ll_debug("ADC are fulfilled err %d\r\n");

   return HAL_ERROR;

  }

  /* Enable the ADC peripheral */

  LL_ADC_Enable(hadc->Instance);

  /* Wait for ADC effectively enabled */

  tickstart = HAL_GetTick();

  while (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == 0UL)

  {

   /* If ADEN bit is set less than 4 ADC clock cycles after the ADCAL bit

     has been cleared (after a calibration), ADEN bit is reset by the

     calibration logic.

     The workaround is to continue setting ADEN until ADRDY is becomes 1.

     Additionally, ADC_ENABLE_TIMEOUT is defined to encompass this

     4 ADC clock cycle duration */

   /* Note: Test of ADC enabled required due to hardware constraint to   */

   /*    not enable ADC if already enabled.               */

   if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)

   {

    LL_ADC_Enable(hadc->Instance);

   }

   if ((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)

   {

    /* Update ADC state machine to error */

    SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);

    /* Set ADC error code to ADC peripheral internal error */

    SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);

    return HAL_ERROR; //!!!!<<<< Always Fail here

   }

  }

 }

 /* Return HAL status */

 return HAL_OK;

}

JNg
Associate II

0693W000004I9VyQAK.png0693W000004I9W8QAK.png0693W000004I9WIQA0.png0693W000004I9WDQA0.png

JNg
Associate II

Hi @Community member​ ,

I found out the root cause of the issue. I have reversed a RAM section in ld file for my debug log. I think my setup is incorrect when I need to change the VTOR address. So what is the correct way to reserved the RAM section in ld file? Please help if you can point out my mistake.

Thank you.  

/* Entry Point */

ENTRY(Reset_Handler)

/* Highest address of the user mode stack */

_estack = 0x20010000; /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x200 ; /* required amount of heap */

_Min_Stack_Size = 0x400 ; /* required amount of stack */

_Debug_Log_Size = 0x2000; /* <<--- reserved 8k Ram for debug log */

__start_of_flash = 0x8004000;

/* Memories definition */

MEMORY

{

 RAM  (xrw)  : ORIGIN = 0x20000000,  LENGTH = 128K

 FLASH  (rx)  : ORIGIN = __start_of_flash,  LENGTH = 446K

}

/* Sections */

SECTIONS

{

 /* The startup code into "FLASH" Rom type memory */

 .isr_vector :

 {

  . = ALIGN(4);

  KEEP(*(.isr_vector)) /* Startup code */

  . = ALIGN(4);

 } >FLASH

 /* The program code and other data into "FLASH" Rom type memory */

 .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 */

 } >FLASH

 /* Constant data into "FLASH" Rom type memory */

 .rodata :

 {

  . = ALIGN(4);

  *(.rodata)     /* .rodata sections (constants, strings, etc.) */

  *(.rodata*)    /* .rodata* sections (constants, strings, etc.) */

  . = ALIGN(4);

 } >FLASH

 .ARM.extab  : { 

  . = ALIGN(4);

  *(.ARM.extab* .gnu.linkonce.armextab.*)

  . = ALIGN(4);

 } >FLASH

  

 .ARM : {

  . = ALIGN(4);

  __exidx_start = .;

  *(.ARM.exidx*)

  __exidx_end = .;

  . = ALIGN(4);

 } >FLASH

 .preinit_array   :

 {

  . = ALIGN(4);

  PROVIDE_HIDDEN (__preinit_array_start = .);

  KEEP (*(.preinit_array*))

  PROVIDE_HIDDEN (__preinit_array_end = .);

  . = ALIGN(4);

 } >FLASH

  

 .init_array :

 {

  . = ALIGN(4);

  PROVIDE_HIDDEN (__init_array_start = .);

  KEEP (*(SORT(.init_array.*)))

  KEEP (*(.init_array*))

  PROVIDE_HIDDEN (__init_array_end = .);

  . = ALIGN(4);

 } >FLASH

  

 .fini_array :

 {

  . = ALIGN(4);

  PROVIDE_HIDDEN (__fini_array_start = .);

  KEEP (*(SORT(.fini_array.*)))

  KEEP (*(.fini_array*))

  PROVIDE_HIDDEN (__fini_array_end = .);

  . = ALIGN(4);

 } >FLASH

 /* Used by the startup to initialize data */

 _sidata = LOADADDR(.data);

 /* Initialized data sections into "RAM" Ram type memory */

 .debug_log : /* <<--- add custom section for debug log */

 {

  . = ALIGN(4);

  _debug_log_addr = .;     /* <<--- create a global symbol at data start */

. = . + _Debug_Log_Size;

  . = ALIGN(4);

 }

 .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 AT> FLASH

 /* Uninitialized data section into "RAM" Ram type memory */

 . = ALIGN(4);

 .bss :

 {

  /* This is used by the startup in order to initialize the .bss section */

  _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

 /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */

 ._user_heap_stack :

 {

  . = ALIGN(8);

  PROVIDE ( end = . );

  PROVIDE ( _end = . );

  . = . + _Min_Heap_Size;

  . = . + _Min_Stack_Size;

  . = ALIGN(8);

 } >RAM

 /* Remove information from the compiler libraries */

 /DISCARD/ :

 {

  libc.a ( * )

  libm.a ( * )

  libgcc.a ( * )

 }

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

}