Skip to content

Update portables for Microchip AVR Dx and Mega0 #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 162 additions & 115 deletions GCC/AVR_AVRDx/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,119 +49,6 @@ extern volatile RTOS_TCB_t * volatile pxCurrentTCB;

/*-----------------------------------------------------------*/

/*
* Macro to save all the general purpose registers, the save the stack pointer
* into the TCB.
*
* The first thing we do is save the flags then disable interrupts. This is to
* guard our stack against having a context switch interrupt after we have already
* pushed the registers onto the stack - causing the 32 registers to be on the
* stack twice.
*
* r1 is set to zero as the compiler expects it to be thus, however some
* of the math routines make use of R1.
*
* The interrupts will have been disabled during the call to portSAVE_CONTEXT()
* so we need not worry about reading/writing to the stack pointer.
*/

#define portSAVE_CONTEXT() \
asm volatile ( "push r0 \n\t" \
"in r0, __SREG__ \n\t" \
"cli \n\t" \
"push r0 \n\t" \
"in r0, __RAMPZ__ \n\t" \
"push r0 \n\t" \
"push r1 \n\t" \
"clr r1 \n\t" \
"push r2 \n\t" \
"push r3 \n\t" \
"push r4 \n\t" \
"push r5 \n\t" \
"push r6 \n\t" \
"push r7 \n\t" \
"push r8 \n\t" \
"push r9 \n\t" \
"push r10 \n\t" \
"push r11 \n\t" \
"push r12 \n\t" \
"push r13 \n\t" \
"push r14 \n\t" \
"push r15 \n\t" \
"push r16 \n\t" \
"push r17 \n\t" \
"push r18 \n\t" \
"push r19 \n\t" \
"push r20 \n\t" \
"push r21 \n\t" \
"push r22 \n\t" \
"push r23 \n\t" \
"push r24 \n\t" \
"push r25 \n\t" \
"push r26 \n\t" \
"push r27 \n\t" \
"push r28 \n\t" \
"push r29 \n\t" \
"push r30 \n\t" \
"push r31 \n\t" \
"lds r26, pxCurrentTCB \n\t" \
"lds r27, pxCurrentTCB + 1 \n\t" \
"in r0, __SP_L__ \n\t" \
"st x+, r0 \n\t" \
"in r0, __SP_H__ \n\t" \
"st x+, r0 \n\t" );

/*
* Opposite to portSAVE_CONTEXT(). Interrupts will have been disabled during
* the context save so we can write to the stack pointer.
*/

#define portRESTORE_CONTEXT() \
asm volatile ( "lds r26, pxCurrentTCB \n\t" \
"lds r27, pxCurrentTCB + 1 \n\t" \
"ld r28, x+ \n\t" \
"out __SP_L__, r28 \n\t" \
"ld r29, x+ \n\t" \
"out __SP_H__, r29 \n\t" \
"pop r31 \n\t" \
"pop r30 \n\t" \
"pop r29 \n\t" \
"pop r28 \n\t" \
"pop r27 \n\t" \
"pop r26 \n\t" \
"pop r25 \n\t" \
"pop r24 \n\t" \
"pop r23 \n\t" \
"pop r22 \n\t" \
"pop r21 \n\t" \
"pop r20 \n\t" \
"pop r19 \n\t" \
"pop r18 \n\t" \
"pop r17 \n\t" \
"pop r16 \n\t" \
"pop r15 \n\t" \
"pop r14 \n\t" \
"pop r13 \n\t" \
"pop r12 \n\t" \
"pop r11 \n\t" \
"pop r10 \n\t" \
"pop r9 \n\t" \
"pop r8 \n\t" \
"pop r7 \n\t" \
"pop r6 \n\t" \
"pop r5 \n\t" \
"pop r4 \n\t" \
"pop r3 \n\t" \
"pop r2 \n\t" \
"pop r1 \n\t" \
"pop r0 \n\t" \
"out __RAMPZ__, r0 \n\t" \
"pop r0 \n\t" \
"out __SREG__, r0 \n\t" \
"pop r0 \n\t" );

/*-----------------------------------------------------------*/

/*
* Perform hardware setup to enable ticks from timer.
*/
Expand Down Expand Up @@ -206,8 +93,10 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
pxTopOfStack--;
*pxTopOfStack = portFLAGS_INT_ENABLED;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x00; /* RAMPZ */
#if defined(__AVR_HAVE_RAMPZ__)
*pxTopOfStack = (StackType_t)0x00; /* RAMPZ */
pxTopOfStack--;
#endif

/* Now the remaining registers. The compiler expects R1 to be 0. */
*pxTopOfStack = ( StackType_t ) 0x00; /* R1 */
Expand Down Expand Up @@ -310,11 +199,15 @@ void vPortYieldFromTick( void )
*/
static void prvSetupTimerInterrupt( void )
{
/* Configure low-power timer used in tickless mode */
#if (configUSE_TICKLESS_IDLE == 1)
RTC_INIT();
#endif
TICK_init();
}
/*-----------------------------------------------------------*/

#if configUSE_PREEMPTION == 1
#if (configUSE_PREEMPTION == 1)

/*
* Tick ISR for preemptive scheduler. We can use a naked attribute as
Expand Down Expand Up @@ -344,3 +237,157 @@ static void prvSetupTimerInterrupt( void )
xTaskIncrementTick();
}
#endif /* if configUSE_PREEMPTION == 1 */

#if (configUSE_TICKLESS_IDLE == 1)

volatile uint32_t RTC_OVF_Count = 0;

ISR(RTC_CNT_vect)
{
if (RTC.INTFLAGS & RTC_OVF_bm )
{
RTC_OVF_Count += 0x00010000;
RTC.INTFLAGS = (RTC_OVF_bm);
}

if (RTC.INTFLAGS & RTC_CMP_bm )
{
RTC.INTFLAGS = (RTC_CMP_bm);
//Disable compare interrupt
RTC.INTCTRL &= (0xFF ^ RTC_CMP_bm);
}

}

static uint32_t ulGetExternalTime(void)
{
uint32_t time_rtc;

while (RTC.STATUS & RTC_CNTBUSY_bm)
{
;
}
time_rtc = RTC.CNT;
time_rtc += RTC_OVF_Count;
return time_rtc;
}

static void vSetWakeTimeInterrupt(uint16_t xExpectedIdleTime)
{
uint32_t rtc_cnt_time;

/* compute the required */
rtc_cnt_time = RTC_TICKS_TO_COUNTS(xExpectedIdleTime);
rtc_cnt_time += ulGetExternalTime();

while (RTC.STATUS & RTC_CMPBUSY_bm)
{
;
}
RTC.CMP = (rtc_cnt_time & 0xFFFF);

//Enable compare interrupt
RTC.INTCTRL |= RTC_CMP_bm;
}

/* Define the function that is called by portSUPPRESS_TICKS_AND_SLEEP(). */
__attribute__((weak)) void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)
{
eSleepModeStatus eSleepStatus;
uint32_t ulLowPowerTimeBeforeSleep, ulLowPowerTimeAfterSleep;

/* Read the current time from a time source that will remain operational
while the microcontroller is in a low power state. */
ulLowPowerTimeBeforeSleep = ulGetExternalTime();

/* Stop the timer that is generating the tick interrupt. */
TICK_TMR_STOP();

/* Enter a critical section that will not effect interrupts bringing the MCU
out of sleep mode. */
portDISABLE_INTERRUPTS();

/* Ensure it is still ok to enter the sleep mode. */
eSleepStatus = eTaskConfirmSleepModeStatus();

if (eSleepStatus == eAbortSleep)
{
/* A task has been moved out of the Blocked state since this macro was
* executed, or a context switch is being held pending. Do not enter a
* sleep state. Restart the tick and exit the critical section. */
TICK_TMR_START();
portENABLE_INTERRUPTS();
}
else
{
if (eSleepStatus == eNoTasksWaitingTimeout)
{
/* A user definable macro that allows application code to be inserted
* here. Such application code can be used to minimize power consumption
* further by turning off IO, peripheral clocks, the Flash, etc. */
configPRE_PWR_DOWN_PROCESSING();

/* There are no running state tasks and no tasks that are blocked with a
* time out. Assuming the application does not care if the tick time slips
* with respect to calendar time then enter a deep sleep that can only be
* woken by (in this demo case) the user button being pushed on the
* Curiosity Nano board. If the application does require the tick time
* to keep better track of the calender time then the PIT peripheral can be
* used to make rough adjustments. */
portSET_MODE_AND_SLEEP(SLEEP_MODE_PWR_DOWN);

/* A user definable macro that allows application code to be inserted
* here. Such application code can be used to reverse any actions taken
* by the configPRE_STOP_PROCESSING() */
configPOST_PWR_DOWN_PROCESSING();
}
else
{
/* Configure an interrupt to bring the microcontroller out of its low
* power state at the time the kernel next needs to execute. The
* interrupt must be generated from a source that remains operational
* when the microcontroller is in a low power state. */
vSetWakeTimeInterrupt(xExpectedIdleTime);

/* Allow the application to define some pre-sleep processing. This is
* the standard configPRE_SLEEP_PROCESSING() macro as described on the
* FreeRTOS.org website. */
configPRE_SLEEP_PROCESSING(xExpectedIdleTime);

/* Enter the low power state. */
portSET_MODE_AND_SLEEP(SLEEP_MODE_STANDBY);

/* Determine how long the microcontroller was actually in a low power
* state for, which will be less than xExpectedIdleTime if the
* microcontroller was brought out of low power mode by an interrupt
* other than that configured by the vSetWakeTimeInterrupt() call.
* Note that the scheduler is suspended before
* portSUPPRESS_TICKS_AND_SLEEP() is called, and resumed when
* portSUPPRESS_TICKS_AND_SLEEP() returns. Therefore no other tasks will
* execute until this function completes. */
ulLowPowerTimeAfterSleep = ulGetExternalTime();

/* Allow the application to define some post sleep processing. This is
* the standard configPOST_SLEEP_PROCESSING() macro, as described on the
* FreeRTOS.org website.
* It can be used to reverse the actions of configPRE_SLEEP_PROCESSING(),
* and in so doing, return the microcontroller back to its fully operational state */
configPOST_SLEEP_PROCESSING(xExpectedIdleTime);

/* Correct the kernels tick count to account for the time the
* microcontroller spent in its low power state. */
vTaskStepTick(RTC_COUNTS_TO_TICKS(ulLowPowerTimeAfterSleep - ulLowPowerTimeBeforeSleep));
// vTaskStepTick(xExpectedIdleTime);

}

/* Exit the critical section - it might be possible to do this immediately
* after the SET_MODE_AND_SLEEP calls. */
portENABLE_INTERRUPTS();

/* Restart the timer that is generating the tick interrupt. */
TICK_TMR_START();
}
}

#endif
Loading