ATSAML21, FreeRTOS works at 4MHz for my application. Breaks when frequency updated to 48MHZ

rishitborad wrote on Wednesday, November 14, 2018:

Discription: When the clock is running on default 4MHz and SYSTEM_CLOCK = 4000000U in system_saml21.c the task scheduler executes and starts the temp_task.

Problem: When the clock is configured to 48MHz through dpll_48MHz_init(), and SYSTEM_CLOCK = 48000000U, it breaks to signal handler in vPortExitCritical() which is called eventually from xTaskCreate(). Please check call_stack in attached file to understand this better.


void main()
{

    /* Update clock freq to 48MHz */ 
    dpll_48MHz_init();

	// Initialize pin MUX
	HW::init();
    
	xTaskCreate(temp_task, "temp_task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    //vTaskStartScheduler();

	while (1) {

		for(int i = 0; i < 10; i++)
		{
			if(i%2 == 0)
			PORT->Group[1].OUTSET.reg |= PORT_PB10;
			else
			PORT->Group[1].OUTCLR.reg |= PORT_PB10;
			for(int j = 0 ; j < 1000000; j++);
		}
		//USART_0_example();
	}
}

vTaskStartScheduler() is disabled for debugging purpose.

I tried to look for the soultion online somewhere it said stack overflow might be the cause which is not the case i think, i treid different stack sizes. Also it would’nt work with 4MHz if that was the case!!! Also, it was suggested that changing SVCInt priority would help. But I think it was specific to M3s so i dint put much efforts to it.

I am unable to figure this out, any help or ideas are appriciated.

Thanks
Rishit

rtel wrote on Wednesday, November 14, 2018:

Looks like you are getting an interrupt [that does not have a handler
installed for it] executing as soon as you exit the critical section.

Calling xTaskCreate() should mask interrupts over
configMAX_SYSCALL_INTERRUPT_PRIORITY until the scheduler has started -
so either the initial critical section nesting count is not being
initialised correctly in your start up code (you can verify this by
checking what value the uxCriticalNesting variable in port.c has when
you are in main()) - or you have an interrupt at a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY executing.

Finding out which interrupt it is would be a good starting point - if it
is a peripheral you will now where to look - if it is a hard or other
fault then it would seem to be a configuration problem.

The only way I could see that this would be dependent on the clock
frequency is that when the frequency is higher the interrupt might occur
much sooner.

rishitborad wrote on Wednesday, November 14, 2018:

Thanks Richard for a quick reply. I implmented handlers and only the HardFault() is being executed. Stepping through, there is no perticular point where it fails i think. Because once it faild when vTaskStartScheduler() is creating an idle task and it makes a call to xTimerCreateTimerTask on line 1948 in tasks.c. What is consistent is it is always a hard fault. is it really configuration issue? What should i look into more?

i tried manipulating configMAX_SYSCALL_INTERRUPT_PRIORITY to no avail, it is set at 2 currently i tried from 0 to 4. I am not sure how to figure out if there are any interrupts with priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.

What surprises me is everything works fine at 4MHz, its 48MHz causing the trouble.

Thanks again.
Regards,
Rishit

rtel wrote on Wednesday, November 14, 2018:

I think the SAML21 is a Cortex-M0 so
configMAX_SYSCALL_INTERRUPT_PRIORITY won’t have any effect (as the M0
does not have a basepri register).

Are you saying the interrupt handler you end up in is the hardfault handler?

Which version of FreeRTOS are you using?

rishitborad wrote on Wednesday, November 14, 2018:

I am using RTOS V10.0.1. I also tried FreeRTOSConfig.h for v10.0.0 from Microchip’s example project to no avail.
And yes I implemented hardFault with a while(1) for the sake of checking if the program ends up there there and it does everytime.

Also, no peripheral except Clock is configured in the project (code above is all i am doing). What are the chances of other interrupts triggering!! I implemented interrupt that handles clock related interrupt but the PC never went there. Also interrupts for the clock are not enabled.

I have attached my FreeRTOSConfig.h file. It has two configs for a version each (V10.0.0 (enabled) & V10.0.1 (disabled)) in case you want to take a look.

rtel wrote on Wednesday, November 14, 2018:

You may have to step through at the assembly level to find the
instruction that results in the fault. In addition - these instructions
are for the Cortex-M3/4/7, not sure how applicable they are to the M0:

https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

rishitborad wrote on Thursday, November 15, 2018:

Thanks Richard for pointing a direction. While i am reading it, I have some more information. I was trying to step thorugh the program (not in assembly) and below are few observations when I am stepping inside the vTaskStartScheduler()

  1. Can not step over these functions, all the calls to these functions gets me to hardfault() if I try to step over.
    - pvPortMalloc()
    - prvAddnewTaskToReadyList()
    - prvProcessTimerOrBlockTask()
    - pvPortMalloc()
    Once I step inside these functions and then steping over eachline in the function works just fine.
  2. Stepping into prvProcessReceivedCommands() generates hardfault directly.
  3. Luckily I was able to run my temp_task() only once by stepping into for a while and run after, I think, vPortStartFirstTask() function. I guess timing was right for that one time.

Doesanything here sound like race condition? I am just driving blind at this point (but working hard). Now I am going to finish reading the documents in your link.

Thanks for you time.

UPDATE: Same FreeRTOS configuration with a different clock scheme works at 48MHz.
The configuration I am trying to work here is using Fractional DPLL. While the one that works at 48MHz uses DFLL.

Does that mean its not a freeRTOS issue but clocking issue?

UPDATE2: In reference to UPDATE above, one of the difference I see in two case i mentiond is PRIMASK is set to 0x01 when the program breaking while it is set to 0x00 when the program running fine.

UPDATE3: Update2 doesnt matter, PRIMASK prevents handling of lower priority (lower than hard_fault?!) exceptions.

rishitborad wrote on Monday, November 19, 2018:

Turns out with ATSAML21, there are different power domains (default PD0). if the CPU clock frequency is more than 12MHz PD2 should be turned on otherwise what I think is bus fault occurs and CPU ends up in the Hard_Fault() (I am assuming, I might be wrong). **Switching on PD2 when running the CPU clock at 48MHz worked for me **(not assuming here :p). Turn on PD2 before configureing the clocks to 48MHz. Information/numbers here might be wrong, refer to the datasheet for accurate information.

rishitborad wrote on Monday, November 19, 2018:

Turns out with ATSAML21, there are different power domains (default PD0). if the CPU clock frequency is more than 12MHz PD2 should be turned on otherwise what I think is bus fault occurs and CPU ends up in the Hard_Fault() (I am assuming, I might be wrong). **Switching on PD2 when running the CPU clock at 48MHz worked for me **(not assuming here :p). Turn on PD2 before configureing the clocks to 48MHz. Information/numbers here might be wrong, refer to the datasheet for accurate information.