/
port.c
2402 lines (2241 loc) · 101 KB
/
port.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
/*-----------------------------------------------------------
* FreeRTOS for 56800EX port by Richy Ye in Jan. 2013.
*----------------------------------------------------------*/
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "portmacro.h" /* for configCPU_FAMILY */
#include "task.h"
#include "portTicks.h" /* for CPU_CORE_CLK_HZ used in configSYSTICK_CLOCK_HZ */
#if configSYSTICK_USE_LOW_POWER_TIMER
#if %@KinetisSDK@'ModuleName'%.CONFIG_NXP_SDK_2_0_USED
#include "fsl_lptmr.h" /* SDK low power timer interface */
#elif %@KinetisSDK@'ModuleName'%.CONFIG_SDK_VERSION_USED == %@KinetisSDK@'ModuleName'%.CONFIG_SDK_PROCESSOR_EXPERT
#include "LPTMR_PDD.h" /* PDD interface to low power timer */
#include "SIM_PDD.h" /* PDD interface to system integration module */
#endif
#endif
#include "%KinetisSDK.h" /* include SDK and API used */
/* --------------------------------------------------- */
/* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case is messes up unwinding of the stack in the
debugger. */
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif
/* --------------------------------------------------- */
/* macros dealing with tick counter */
%if (CPUfamily = "Kinetis")
#if configSYSTICK_USE_LOW_POWER_TIMER
#if !%@KinetisSDK@'ModuleName'%.CONFIG_PEX_SDK_USED
/*! \todo */
#define LPTMR0_BASE_PTR LPTMR0 /* low power timer address base */
#define configLOW_POWER_TIMER_VECTOR_NUMBER LPTMR0_IRQn /* low power timer IRQ number */
#define ENABLE_TICK_COUNTER() LPTMR_StartTimer(LPTMR0_BASE_PTR); LPTMR_EnableInterrupts(LPTMR0_BASE_PTR, kLPTMR_TimerInterruptEnable)
#define DISABLE_TICK_COUNTER() LPTMR_StopTimer(LPTMR0_BASE_PTR)
#define RESET_TICK_COUNTER_VAL() LPTMR_StopTimer(LPTMR0_BASE_PTR); LPTMR_DisableInterrupts(LPTMR0_BASE_PTR, kLPTMR_TimerInterruptEnable)
#define ACKNOWLEDGE_TICK_ISR() LPTMR_ClearStatusFlags(LPTMR0_BASE_PTR, kLPTMR_TimerCompareFlag);
#elif %@KinetisSDK@'ModuleName'%.CONFIG_SDK_VERSION_USED == %@KinetisSDK@'ModuleName'%.CONFIG_SDK_PROCESSOR_EXPERT
#define ENABLE_TICK_COUNTER() LPTMR_PDD_EnableDevice(LPTMR0_BASE_PTR, PDD_ENABLE); LPTMR_PDD_EnableInterrupt(LPTMR0_BASE_PTR)
#define DISABLE_TICK_COUNTER() LPTMR_PDD_EnableDevice(LPTMR0_BASE_PTR, PDD_DISABLE); LPTMR_PDD_DisableInterrupt(LPTMR0_BASE_PTR)
#define RESET_TICK_COUNTER_VAL() DISABLE_TICK_COUNTER() /* CNR is reset when the LPTMR is disabled or counter register overflows */
#define ACKNOWLEDGE_TICK_ISR() LPTMR_PDD_ClearInterruptFlag(LPTMR0_BASE_PTR)
#if defined(LDD_ivIndex_INT_LPTimer) /* Earlier version of Processor Expert use this vector name */
#define configLOW_POWER_TIMER_VECTOR_NUMBER LDD_ivIndex_INT_LPTimer
#elif defined(LDD_ivIndex_INT_LPTMR0) /* Newer versions (Processor Expert for Kinetis v3.0.1 uses this name */
#define configLOW_POWER_TIMER_VECTOR_NUMBER LDD_ivIndex_INT_LPTMR0
#else
#error "Unknown Low Power Timer Interrupt Number?"
#endif
#endif
#else
#define ENABLE_TICK_COUNTER() portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT
#define DISABLE_TICK_COUNTER() portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT
#define RESET_TICK_COUNTER_VAL() portNVIC_SYSTICK_CURRENT_VALUE_REG = 0 /*portNVIC_SYSTICK_LOAD_REG*/
#define ACKNOWLEDGE_TICK_ISR() /* not needed */
#endif
%elif defined(TickCntr)
#define ENABLE_TICK_COUNTER() (void)%@TickCntr@'ModuleName'%.Enable()
#define DISABLE_TICK_COUNTER() (void)%@TickCntr@'ModuleName'%.Disable()
%if defined(TickCntr) & defined(@TickCntr@Reset)
#define RESET_TICK_COUNTER_VAL() (void)%@TickCntr@'ModuleName'%.Reset()
%else
#define RESET_TICK_COUNTER_VAL() /* WARNING: not possible to reset tick timer! */
%endif
%elif defined(TickTimerLDD)
#define ENABLE_TICK_COUNTER() (void)%@TickTimerLDD@'ModuleName'%.Enable(RTOS_TickDevice)
#define DISABLE_TICK_COUNTER() (void)%@TickTimerLDD@'ModuleName'%.Disable(RTOS_TickDevice)
#define RESET_TICK_COUNTER_VAL() portNVIC_SYSTICK_CURRENT_VALUE_REG = 0 /*portNVIC_SYSTICK_LOAD_REG*/
%endif
%if (CPUfamily = "Kinetis")
typedef unsigned long TickCounter_t; /* enough for 24 bit Systick */
#if configSYSTICK_USE_LOW_POWER_TIMER
#define TICK_NOF_BITS 16
#define COUNTS_UP 1 /* LPTMR is counting up */
#if !%@KinetisSDK@'ModuleName'%.CONFIG_PEX_SDK_USED
#define SET_TICK_DURATION(val) LPTMR_SetTimerPeriod(LPTMR0_BASE_PTR, val);
#define GET_TICK_DURATION() LPTMR0_BASE_PTR->CNR /*! \todo SDK has no access method for this */
#define GET_TICK_CURRENT_VAL(addr) *(addr)=LPTMR_GetCurrentTimerCount(LPTMR0_BASE_PTR)
#else
#define SET_TICK_DURATION(val) LPTMR_PDD_WriteCompareReg(LPTMR0_BASE_PTR, val)
#define GET_TICK_DURATION() LPTMR_PDD_ReadCompareReg(LPTMR0_BASE_PTR)
#define GET_TICK_CURRENT_VAL(addr) *(addr)=LPTMR_PDD_ReadCounterReg(LPTMR0_BASE_PTR)
#endif
#else
#define TICK_NOF_BITS 24
#define COUNTS_UP 0 /* SysTick is counting down to zero */
#define SET_TICK_DURATION(val) portNVIC_SYSTICK_LOAD_REG = val
#define GET_TICK_DURATION() portNVIC_SYSTICK_LOAD_REG
#define GET_TICK_CURRENT_VAL(addr) *(addr)=portNVIC_SYSTICK_CURRENT_VALUE_REG
#endif
%elif defined(TickCntr)
#define TICK_NOF_BITS 16
#define COUNTS_UP %@TickCntr@'ModuleName'%.UP_COUNTER
typedef %@TickCntr@'ModuleName'%.TTimerValue TickCounter_t; /* for holding counter */
#if configUSE_TICKLESS_IDLE == 1
static TickCounter_t currTickDuration; /* holds the modulo counter/tick duration as no API to get it from the FreeCntr component */
#endif
#define SET_TICK_DURATION(val) (void)%@TickCntr@'ModuleName'%.SetCompare((%@TickCntr@'ModuleName'%.TTimerValue)(val)); currTickDuration=(TickCounter_t)(val)
#define GET_TICK_DURATION() currTickDuration
#define GET_TICK_CURRENT_VAL(addr) (void)%@TickCntr@'ModuleName'%.GetCounterValue(addr)
%endif
#if configSYSTICK_USE_LOW_POWER_TIMER
#define TIMER_COUNTS_FOR_ONE_TICK (configSYSTICK_LOW_POWER_TIMER_CLOCK_HZ/configTICK_RATE_HZ)
#else
#define TIMER_COUNTS_FOR_ONE_TICK (configSYSTICK_CLOCK_HZ/configTICK_RATE_HZ)
#endif
#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS && configCPU_FAMILY==configCPU_FAMILY_ARM_M0P
unsigned int SEGGER_SYSVIEW_TickCnt; /* tick counter for Segger SystemViewer */
#endif
#if configUSE_TICKLESS_IDLE
#define UL_TIMER_COUNTS_FOR_ONE_TICK ((TickCounter_t)(TIMER_COUNTS_FOR_ONE_TICK))
#if configCPU_FAMILY_IS_ARM(configCPU_FAMILY)
#define TICKLESS_DISABLE_INTERRUPTS() __asm volatile("cpsid i") /* disable interrupts. Note that the wfi (wait for interrupt) instruction later will still be able to wait for interrupts! */
#define TICKLESS_ENABLE_INTERRUPTS() __asm volatile("cpsie i") /* re-enable interrupts. */
#elif (configCPU_FAMILY==configCPU_FAMILY_S08) || (configCPU_FAMILY==configCPU_FAMILY_S12)
#define TICKLESS_DISABLE_INTERRUPTS() __asm("sei"); /* disable interrupts */
#define TICKLESS_ENABLE_INTERRUPTS() __asm("cli"); /* re-enable interrupts */
#else
#define TICKLESS_DISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() /* this disables interrupts! Make sure they are re-enabled in vOnPreSleepProcessing()! */
#define TICKLESS_ENABLE_INTERRUPTS() portENABLE_INTERRUPTS() /* re-enable interrupts */
#endif
%if defined(useARMSysTickTimer) & useARMSysTickTimer='yes'
#if 1
%else
#if 0
%endif
#if configSYSTICK_USE_LOW_POWER_TIMER
/* using Low Power Timer */
#if CONFIG_PEX_SDK_USED%@KinetisSDK@'ModuleName'%.CONFIG_PEX_SDK_USED
#define LPTMR_CSR_TCF_MASK 0x80u
#define TICK_INTERRUPT_HAS_FIRED() (LPTMR0_BASE_PTR->CSR&LPTMR_CSR_TCF_MASK)!=0/*! \todo */ /* returns TRUE if tick interrupt had fired */
#else
#define TICK_INTERRUPT_HAS_FIRED() (LPTMR_PDD_GetInterruptFlag(LPTMR0_BASE_PTR)!=0) /* returns TRUE if tick interrupt had fired */
#endif
#define TICK_INTERRUPT_FLAG_RESET() /* not needed */
#define TICK_INTERRUPT_FLAG_SET() /* not needed */
#else
/* using directly SysTick Timer */
#define TICK_INTERRUPT_HAS_FIRED() ((portNVIC_SYSTICK_CTRL_REG&portNVIC_SYSTICK_COUNT_FLAG_BIT)!=0) /* returns TRUE if tick interrupt had fired */
#define TICK_INTERRUPT_FLAG_RESET() /* not needed */
#define TICK_INTERRUPT_FLAG_SET() /* not needed */
#endif
#else
/* using global variable to find out if interrupt has fired */
volatile uint8_t portTickCntr; /* used to find out if we woke up by the tick interrupt */
#define TICK_INTERRUPT_HAS_FIRED() (portTickCntr!=0) /* returns TRUE if tick interrupt had fired */
#define TICK_INTERRUPT_FLAG_RESET() portTickCntr=0
#define TICK_INTERRUPT_FLAG_SET() portTickCntr=1
#endif
#endif /* configUSE_TICKLESS_IDLE == 1 */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* resolution of the tick timer.
*/
#if configUSE_TICKLESS_IDLE == 1
static TickCounter_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the tick timer is stopped (low
* power functionality only).
*/
#if configUSE_TICKLESS_IDLE == 1
static TickCounter_t ulStoppedTimerCompensation = 0; /* number of timer ticks to compensate */
%if defined(StoppedTimerCompensation)
#define configSTOPPED_TIMER_COMPENSATION %'StoppedTimerCompensation'UL /* number of CPU cycles to compensate, as defined in properties. ulStoppedTimerCompensation will contain the number of timer ticks. */
%else
#define configSTOPPED_TIMER_COMPENSATION 45UL /* number of CPU cycles to compensate. ulStoppedTimerCompensation will contain the number of timer ticks. */
%endif
#endif /* configUSE_TICKLESS_IDLE */
/* Flag indicating that the tick counter interval needs to be restored back to
* the normal setting. Used when woken up from a low power mode using the LPTMR.
*/
#if configUSE_TICKLESS_IDLE && configSYSTICK_USE_LOW_POWER_TIMER
static uint8_t restoreTickInterval = 0; /* used to flag in tick ISR that compare register needs to be reloaded */
#endif
#if (configCPU_FAMILY==configCPU_FAMILY_CF1) || (configCPU_FAMILY==configCPU_FAMILY_CF2)
#define portINITIAL_FORMAT_VECTOR ((portSTACK_TYPE)0x4000)
#define portINITIAL_STATUS_REGISTER ((portSTACK_TYPE)0x2000) /* Supervisor mode set. */
#endif
#if configCPU_FAMILY_IS_ARM(configCPU_FAMILY)
/* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* Constants required to manipulate the core.
* SysTick register: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0662b/CIAGECDD.html
* Registers first...
*/
#define portNVIC_SYSTICK_CTRL_REG (*((volatile unsigned long *)0xe000e010)) /* SYST_CSR, SysTick Control and Status Register */
#define portNVIC_SYSTICK_LOAD_REG (*((volatile unsigned long *)0xe000e014)) /* SYST_RVR, SysTick reload value register */
#define portNVIC_SYSTICK_CURRENT_VALUE_REG (*((volatile unsigned long *)0xe000e018)) /* SYST_CVR, SysTick current value register */
#define portNVIC_SYSTICK_CALIB_VALUE_REG (*((volatile unsigned long *)0xe000e01C)) /* SYST_CALIB, SysTick calibration value register */
/* ...then bits in the registers. */
#define portNVIC_SYSTICK_COUNT_FLAG_BIT (1UL<<16UL) /* returns 1 if timer counted to 0 since the last read of the register */
#if configSYSTICK_USE_CORE_CLOCK
#define portNVIC_SYSTICK_CLK_BIT (1UL<<2UL) /* clock source. 1: core clock, 0: external reference clock */
#else
#define portNVIC_SYSTICK_CLK_BIT (0UL<<2UL) /* clock source. 1: core clock, 0: external reference clock */
#endif
#define portNVIC_SYSTICK_INT_BIT (1UL<<1UL) /* SysTick interrupt enable bit */
#define portNVIC_SYSTICK_ENABLE_BIT (1UL<<0UL) /* SysTick enable bit */
/* Constants required to manipulate the NVIC: */
#define portNVIC_INT_CTRL ((volatile unsigned long*)0xe000ed04) /* interrupt control and state register (ICSR) */
#define portNVIC_PENDSVSET_BIT (1UL<<28UL) /* bit 28 in portNVIC_INT_CTRL (PENDSVSET), see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihfaaha.html */
#define portNVIC_PENDSVCLEAR_BIT (1UL<<27UL) /* bit 27 in portNVIC_INT_CTRL (PENDSVCLR) */
#define portNVIC_PEND_SYSTICK_SET_BIT (1UL<<26UL) /* bit 26 in portNVIC_INT_CTRL (PENDSTSET) */
#define portNVIC_PEND_SYSTICK_CLEAR_BIT (1UL<<25UL) /* bit 25 in portNVIC_INT_CTRL (PENDSTCLR) */
#define portNVIC_SYSPRI2 ((volatile unsigned long*)0xe000ed1c) /* system handler priority register 2 (SHPR2), used for SVCall priority, http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0662b/CIAGECDD.html */
#define portNVIC_SVCALL_PRI (((unsigned long)configKERNEL_INTERRUPT_PRIORITY)<<24) /* priority of SVCall interrupt (in portNVIC_SYSPRI2) */
#define portNVIC_SYSPRI3 ((volatile unsigned long*)0xe000ed20) /* system handler priority register 3 (SHPR3), used for SysTick and PendSV priority, http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0662b/CIAGECDD.html */
#define portNVIC_SYSTICK_PRI (((unsigned long)configKERNEL_INTERRUPT_PRIORITY)<<24) /* priority of SysTick interrupt (in portNVIC_SYSPRI3) */
#define portNVIC_PENDSV_PRI (((unsigned long)configKERNEL_INTERRUPT_PRIORITY)<<16) /* priority of PendableService interrupt (in portNVIC_SYSPRI3) */
#define portNVIC_SYSPRI7 ((volatile unsigned long*)0xe000e41c) /* system handler priority register 7, PRI_28 is LPTMR */
#define portNVIC_LP_TIMER_PRI (((unsigned long)configKERNEL_INTERRUPT_PRIORITY)<<0) /* priority of low power timer interrupt */
#if configSYSTICK_USE_LOW_POWER_TIMER && %@KinetisSDK@'ModuleName'%.CONFIG_SDK_VERSION_USED == %@KinetisSDK@'ModuleName'%.CONFIG_SDK_PROCESSOR_EXPERT
#define IRQn_Type int
#define __NVIC_PRIO_BITS configPRIO_BITS
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
*/
#if configCPU_FAMILY_IS_ARM_M4_M7(configCPU_FAMILY)
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */
} NVIC_Type;
#else /* M0+ */
typedef struct
{
__IO uint32_t ISER[1]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[31];
__IO uint32_t ICER[1]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[31];
__IO uint32_t ISPR[1]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[31];
__IO uint32_t ICPR[1]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[31];
uint32_t RESERVED4[64];
__IO uint32_t IP[8]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
} NVIC_Type;
#endif
/* Memory mapping of Cortex-M0+ Hardware */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
/* Interrupt Priorities are WORD accessible only under ARMv6M */
/* The following MACROS handle generation of the register offset and byte masks */
#define _BIT_SHIFT(IRQn) ( (((uint32_t)(IRQn) ) & 0x03) * 8 )
#define _IP_IDX(IRQn) ( ((uint32_t)(IRQn) >> 2) )
/** \brief Set Interrupt Priority
The function sets the priority of an interrupt.
\note The priority cannot be set for every core interrupt.
\param [in] IRQn Interrupt number.
\param [in] priority Priority to set.
*/
static void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) {
IRQn -= 16; /* PEx starts numbers with zero, while system interrupts would be negative */
#if configCPU_FAMILY_IS_ARM_M4_M7(configCPU_FAMILY)
NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); /* set Priority for device specific Interrupts */
#else /* M0+ */
NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); /* set Priority for device specific Interrupts */
#endif
}
/** \brief Enable External Interrupt
The function enables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
static void NVIC_EnableIRQ(IRQn_Type IRQn) {
IRQn -= 16; /* PEx starts numbers with zero, while system interrupts would be negative */
#if configCPU_FAMILY_IS_ARM_M4_M7(configCPU_FAMILY)
NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5] = (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); /* enable interrupt */
#else /* M0+ */
NVIC->ISER[0] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */
#endif
}
#endif /* configSYSTICK_USE_LOW_POWER_TIMER */
/* Constants required to set up the initial stack. */
#define portINITIAL_XPSR (0x01000000)
#define portINITIAL_EXEC_RETURN (0xfffffffd)
#define portINITIAL_CONTROL_IF_UNPRIVILEGED (0x03)
#define portINITIAL_CONTROL_IF_PRIVILEGED (0x02)
#if configCPU_FAMILY_IS_ARM_FPU(configCPU_FAMILY)
/* Constants required to manipulate the VFP. */
#define portFPCCR ((volatile unsigned long *)0xe000ef34) /* Floating point context control register. */
#define portASPEN_AND_LSPEN_BITS (0x3UL<<30UL)
#endif
%-
%if defined(TickTimerLDD)
static LDD_TDeviceData *RTOS_TickDevice;
%endif
#endif
%--------------------------------------------------------------
/* Used to keep track of the number of nested calls to taskENTER_CRITICAL().
This will be set to 0 prior to the first task being started. */
%if (CPUfamily = "ColdFireV1") | (CPUfamily = "MCF")
unsigned portLONG uxCriticalNesting = 0x9999UL;
%elif (CPUfamily = "HCS08") | (CPUfamily = "HC08") | (CPUfamily = "HCS12") | (CPUfamily = "HCS12X") | (CPUfamily = "56800")
volatile unsigned portBASE_TYPE uxCriticalNesting;
%elif (CPUfamily = "Kinetis")
/* Each task maintains its own interrupt status in the critical nesting variable. */
static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa;
%else
#error "undefined target %CPUfamily!"
%endif
#if INCLUDE_vTaskEndScheduler
#include <setjmp.h>
static jmp_buf xJumpBuf; /* Used to restore the original context when the scheduler is ended. */
#endif
/*-----------------------------------------------------------*/
void prvTaskExitError(void) {
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */
configASSERT(uxCriticalNesting == ~0UL);
portDISABLE_INTERRUPTS();
for(;;) {
/* wait here */
}
}
/*-----------------------------------------------------------*/
#if (configCOMPILER==configCOMPILER_ARM_KEIL) && configCPU_FAMILY_IS_ARM_M4_M7(configCPU_FAMILY)
__asm uint32_t ulPortSetInterruptMask(void) {
PRESERVE8
mrs r0, basepri
mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r1
bx r14
}
#endif /* (configCOMPILER==configCOMPILER_ARM_KEIL) */
/*-----------------------------------------------------------*/
#if (configCOMPILER==configCOMPILER_ARM_KEIL) && configCPU_FAMILY_IS_ARM_M4_M7(configCPU_FAMILY)
__asm void vPortClearInterruptMask(uint32_t ulNewMask) {
PRESERVE8
msr basepri, r0
bx r14
}
#endif /* (configCOMPILER==configCOMPILER_ARM_KEIL) */
/*-----------------------------------------------------------*/
%if (CPUfamily = "56800")
/* We require the address of the pxCurrentTCB variable, but don't want to know any details of its type. */
typedef void tskTCB;
extern tskTCB *volatile pxCurrentTCB;
#define portSAVE_CONTEXT() do {\
__asm(ADDA #<2,SP); /* SP is always long aligned */\
__asm(BFTSTL #$0001,SP);\
__asm(BCC NOADDASAVE);\
__asm(ADDA #<1,SP);\
__asm(NOADDASAVE:);\
__asm(MOVE.L SR, X:(SP)+);\
__asm(BFSET #0x0300,SR); /* Disable interrupt */\
__asm(MOVE.L R0, X:(SP)+);\
__asm(MOVE.L R1, X:(SP)+);\
__asm(MOVE.L R2, X:(SP)+);\
__asm(MOVE.L R3, X:(SP)+);\
__asm(MOVE.L R4, X:(SP)+);\
__asm(MOVE.L R5, X:(SP)+);\
__asm(MOVE.L N, X:(SP)+);\
__asm(MOVE.L N3, X:(SP)+);\
__asm(MOVE.L LC2,X:(SP)+);\
__asm(MOVE.L LA2,X:(SP)+);\
__asm(MOVE.L LC,X:(SP)+);\
__asm(MOVE.L LA,X:(SP)+);\
__asm(MOVE.L A2,X:(SP)+);\
__asm(MOVE.L A10,X:(SP)+);\
__asm(MOVE.L B2,X:(SP)+);\
__asm(MOVE.L B10,X:(SP)+);\
__asm(MOVE.L C2,X:(SP)+);\
__asm(MOVE.L C10,X:(SP)+);\
__asm(MOVE.L D2,X:(SP)+);\
__asm(MOVE.L D10,X:(SP)+);\
__asm(MOVE.L X0,X:(SP)+);\
__asm(MOVE.L Y,X:(SP)+);\
__asm(MOVE.L OMR,X:(SP)+);\
__asm(BFCLR #0x01B0,OMR); /* Ensure CM = 0 */\
__asm(MOVE.L M01,X:(SP)+);\
__asm(BFSET #0xFFFF,M01); /* Set M01 for linear addressing */\
__asm(MOVE.L HWS,X:(SP)+);\
__asm(MOVE.L HWS,X:(SP)+);\
__asm(MOVE.L uxCriticalNesting,A);\
__asm(MOVE.L A10,X:(SP)+); /* Save the critical nesting counter */\
__asm(MOVE.L pxCurrentTCB,R0);\
__asm(TFRA SP,R1); /* Save the new top of stack into the TCB */\
__asm(MOVE.L R1,X:(R0));\
} while(0)
#define portRESTORE_CONTEXT() do {\
__asm(MOVE.L pxCurrentTCB,R0); /* Restore the stack pointer for the task */\
__asm(MOVE.L X:(R0),R1);\
__asm(BFTSTL #$0001,R1);\
__asm(BCC NOADDARESTORE);\
__asm(ADDA #<1,R1);\
__asm(NOADDARESTORE:);\
__asm(TFRA R1,SP);\
__asm(SUBA #<2,SP);\
__asm(MOVE.L X:(SP)-,A);\
__asm(MOVE.L A10,uxCriticalNesting); /* Restore the critical nesting counter */\
__asm(MOVE.L X:(SP)-,HWS);\
__asm(MOVE.L X:(SP)-,HWS);\
__asm(MOVE.L X:(SP)-,M01);\
__asm(MOVE.L X:(SP)-,OMR);\
__asm(MOVE.L X:(SP)-,Y);\
__asm(MOVE.L X:(SP)-,X0);\
__asm(MOVE.L X:(SP)-,D);\
__asm(MOVE.L X:(SP)-,D2);\
__asm(MOVE.L X:(SP)-,C);\
__asm(MOVE.L X:(SP)-,C2);\
__asm(MOVE.L X:(SP)-,B);\
__asm(MOVE.L X:(SP)-,B2);\
__asm(MOVE.L X:(SP)-,A);\
__asm(MOVE.L X:(SP)-,A2);\
__asm(MOVE.L X:(SP)-,LA);\
__asm(MOVE.L X:(SP)-,LC);\
__asm(MOVE.L X:(SP)-,LA2);\
__asm(MOVE.L X:(SP)-,LC2);\
__asm(MOVE.L X:(SP)-,N3);\
__asm(MOVE.L X:(SP)-,N);\
__asm(MOVE.L X:(SP)-,R5);\
__asm(MOVE.L X:(SP)-,R4);\
__asm(MOVE.L X:(SP)-,R3);\
__asm(MOVE.L X:(SP)-,R2);\
__asm(MOVE.L X:(SP)-,R1);\
__asm(MOVE.L X:(SP)-,R0);\
__asm(MOVE.L X:(SP)-,SR);\
} while(0)
%endif %- (CPUfamily = "56800")
%- -------------------------------------------------------------------------------------
%if (CPUfamily = "ColdFireV1") | (CPUfamily = "MCF")
StackType_t *pxPortInitialiseStack(portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters) {
unsigned portLONG ulOriginalA5;
__asm{ MOVE.L A5, ulOriginalA5 };
*pxTopOfStack = (portSTACK_TYPE)0xDEADBEEF;
pxTopOfStack--;
/* Exception stack frame starts with the return address. */
*pxTopOfStack = (portSTACK_TYPE)pxCode;
pxTopOfStack--;
*pxTopOfStack = (portINITIAL_FORMAT_VECTOR<<16UL) | ( portINITIAL_STATUS_REGISTER );
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)0x0; /*FP*/
pxTopOfStack -= 14; /* A5 to D0. */
/* Parameter in A0. */
*(pxTopOfStack + 8) = (portSTACK_TYPE)pvParameters;
/* A5 must be maintained as it is reserved by the compiler. */
*(pxTopOfStack + 13) = ulOriginalA5;
return pxTopOfStack;
}
%elif (CPUfamily = "HCS08") | (CPUfamily = "HC08")
StackType_t *pxPortInitialiseStack(portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters) {
/* Set as task caller the prvTaskExitError function. */
*pxTopOfStack = (uint8_t)portTASK_RETURN_ADDRESS;
pxTopOfStack--;
*pxTopOfStack = (uint8_t)(((uint16_t)portTASK_RETURN_ADDRESS)>>8);
pxTopOfStack--;
/* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT() macro. In this case the stack as
expected by the HCS08 RTI instruction.
When compiling with the -Cs08 options the value of pvParameters needs to show up in the
H:X registers, but the RTI does not restore H. We'll push it onto the stack here, and
later in restoreContext we'll pull it out just before the RTI call. */
/* The address of the task function is placed in the stack byte at a time. */
#ifdef __BANKED__
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pxCode))+2);
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pxCode))+1);
pxTopOfStack--;
#else
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pxCode))+1);
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pxCode))+0);
pxTopOfStack--;
#endif
/* Next are all the registers that form part of the task context. */
/* X register: We need this even though we pull H:X out of the stack during restore since RTI will overwrite the X reg. */
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pvParameters))+1);
pxTopOfStack--;
/* A register contains parameter high byte. */
*pxTopOfStack = (portSTACK_TYPE) 0xdd;
pxTopOfStack--;
/* CCR: Note that when the task starts interrupts will be enabled since "I" bit of CCR is cleared */
*pxTopOfStack = (portSTACK_TYPE) 0x00;
pxTopOfStack--;
/* H register: This is not part of RTI setup, but we will store the H reg just before the call to RTI. */
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pvParameters))+0);
pxTopOfStack--;
#ifdef __BANKED__
/* The page of the task. */
*pxTopOfStack = (portSTACK_TYPE) *(((portSTACK_TYPE*)(&pxCode))+0);
pxTopOfStack--;
#endif
/* Finally the critical nesting depth is initialized with 0 (not within a critical section). */
*pxTopOfStack = (portSTACK_TYPE) 0x00;
return pxTopOfStack;
}
%elif (CPUfamily = "HCS12") | (CPUfamily = "HCS12X")
StackType_t *pxPortInitialiseStack(portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters) {
/*Place a few bytes of known values on the bottom of the stack.
This can be uncommented to provide useful stack markers when debugging.
*pxTopOfStack = (portSTACK_TYPE)0x11;
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)0x22;
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)0x33;
pxTopOfStack--;
*/
/* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT() macro. In this case the stack as
expected by the HCS12 RTI instruction. */
/* The address of the task function is placed in the stack byte at a time. */
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pxCode))+1);
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pxCode))+0);
pxTopOfStack--;
/* Next are all the registers that form part of the task context. */
/* Y register */
*pxTopOfStack = (portSTACK_TYPE)0xff;
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)0xee;
pxTopOfStack--;
/* X register */
*pxTopOfStack = (portSTACK_TYPE)0xdd;
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)0xcc;
pxTopOfStack--;
/* A register contains parameter high byte. */
*pxTopOfStack = (portSTACK_TYPE) *(((portSTACK_TYPE*)(&pvParameters))+0);
pxTopOfStack--;
/* B register contains parameter low byte. */
*pxTopOfStack = (portSTACK_TYPE)*(((portSTACK_TYPE*)(&pvParameters))+1);
pxTopOfStack--;
#ifdef __HCS12X__
/* CCR (12-bit): Note that when the task starts interrupts will be enabled since I" bit of CCR is cleared */
*pxTopOfStack = (portSTACK_TYPE)0xC0;
pxTopOfStack--;
*pxTopOfStack = (portSTACK_TYPE)0x00;
pxTopOfStack--;
#else
/* CCR(8-bit): Note that when the task starts interrupts will be enabled since "I" bit of CCR is cleared */
*pxTopOfStack = (portSTACK_TYPE)0x40; /* have the X bit still masked */
pxTopOfStack--;
#endif
#ifdef __BANKED__
#ifdef __HCS12X__
*pxTopOfStack = (portSTACK_TYPE) *(((portSTACK_TYPE*)(&pxCode))+2); /* PPage of task created */
pxTopOfStack--;
*pxTopOfStack = EPAGE;
pxTopOfStack--;
*pxTopOfStack = GPAGE;
pxTopOfStack--;
*pxTopOfStack = RPAGE;
pxTopOfStack--;
#else
/* The page of the task. */
*pxTopOfStack = (portSTACK_TYPE)((int)pxCode);
pxTopOfStack--;
#endif
#endif
/* Finally the critical nesting depth is initialised with 0 (not within a critical section). */
*pxTopOfStack = (portSTACK_TYPE)0x00;
return pxTopOfStack;
}
%elif (CPUfamily = "Kinetis")
#if configUSE_MPU_SUPPORT
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged) {
#else
StackType_t *pxPortInitialiseStack(portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters) {
#endif
/* Simulate the stack frame as it would be created by a context switch interrupt. */
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts, and to ensure alignment. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
#if configUSE_MPU_SUPPORT
*pxTopOfStack = ((StackType_t)pxCode)&portSTART_ADDRESS_MASK; /* PC */
#else
*pxTopOfStack = ((StackType_t)pxCode); /* PC */
#endif
pxTopOfStack--;
*pxTopOfStack = (StackType_t)portTASK_RETURN_ADDRESS; /* LR */
/* Save code space by skipping register initialization. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = (portSTACK_TYPE)pvParameters; /* R0 */
#if configCPU_FAMILY_IS_ARM_FPU(configCPU_FAMILY) /* has floating point unit */
/* A save method is being used that requires each task to maintain its
own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXEC_RETURN;
#endif
#if configUSE_MPU_SUPPORT
pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4 plus priviledge level */
if (xRunPrivileged == pdTRUE) {
*pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;
} else {
*pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;
}
#else
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
#endif
return pxTopOfStack;
}
%elif (CPUfamily = "56800")
StackType_t *pxPortInitialiseStack(portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters) {
#define portINITIAL_SR 0x00UL
unsigned short usCode;
portBASE_TYPE i;
const portSTACK_TYPE xInitialStack[] =
{
0x03030303UL, /* R3 */
0x04040404UL, /* R4 */
0x05050505UL, /* R5 */
0x06060606UL, /* N */
0x07070707UL, /* N3 */
0x08080808UL, /* LC2 */
0x09090909UL, /* LA2 */
0x0A0A0A0AUL, /* LC */
0x0B0B0B0BUL, /* LA */
0x0E0E0E0EUL, /* A2 */
0x0F0F0F0FUL, /* A10 */
0x11111111UL, /* B2 */
0x22222222UL, /* B10 */
0x33333333UL, /* C2 */
0x44444444UL, /* C10 */
0x55555555UL, /* D2 */
0x66666666UL, /* D10 */
0x77777777UL, /* X0 */
0x88888888UL /* Y */
};
/* Setup the stack as if a yield had occurred. Save the program counter. */
*pxTopOfStack = ( portSTACK_TYPE ) pxCode;
pxTopOfStack++;
/* Status register with interrupts enabled. */
*pxTopOfStack = portINITIAL_SR;
pxTopOfStack++;
/* Address register R0 */
*pxTopOfStack = 0x0000000UL;
pxTopOfStack++;
/* Address register R1 */
*pxTopOfStack = 0x01010101UL;
pxTopOfStack++;
/* Parameters are passed in R2. */
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters;
pxTopOfStack++;
for( i = 0; i < ( sizeof( xInitialStack ) / sizeof( portSTACK_TYPE ) ); i++ )
{
*pxTopOfStack = xInitialStack[ i ];
pxTopOfStack++;
}
/* Operation mode register */
__asm(MOVE.W OMR,usCode);
*pxTopOfStack = ( portSTACK_TYPE ) usCode;
pxTopOfStack++;
/* Modulo register */
__asm(MOVE.W M01,usCode);
*pxTopOfStack = ( portSTACK_TYPE ) usCode;
pxTopOfStack++;
/* Hardware stack register 1 */
*pxTopOfStack = 0x0C0C0C0CUL;
pxTopOfStack++;
/* Hardware stack register 0 */
*pxTopOfStack = 0x0D0D0D0DUL;
pxTopOfStack++;
/* Finally the critical nesting depth. */
*pxTopOfStack = 0x00000000UL;
pxTopOfStack++;
return pxTopOfStack;
}
%else
StackType_t *pxPortInitialiseStack(portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters) {
%warning "unsupported target %CPUfamily!"
#error "unsupported target %CPUfamily!"
return 0;
}
%endif
/*-----------------------------------------------------------*/
#if (configCOMPILER==configCOMPILER_S08_FSL) || (configCOMPILER==configCOMPILER_S12_FSL)
#if (configCOMPILER==configCOMPILER_S08_FSL)
#pragma MESSAGE DISABLE C1404 /* return expected */
#pragma MESSAGE DISABLE C20000 /* dead code detected */
#pragma NO_RETURN
#pragma CODE_SEG __NEAR_SEG NON_BANKED
#elif (configCOMPILER==configCOMPILER_S12_FSL)
#pragma MESSAGE DISABLE C1404 /* return expected */
#pragma NO_RETURN
#endif
static portBASE_TYPE xBankedStartScheduler(void) {
/* Restore the context of the first task. */
portRESTORE_CONTEXT(); /* Simulate the end of an interrupt to start the scheduler off. */
/* Should not get here! */
return pdFALSE;
}
#if (configCOMPILER==configCOMPILER_S08_FSL)
#pragma CODE_SEG DEFAULT
#pragma MESSAGE DEFAULT C1404 /* return expected */
#pragma MESSAGE DEFAULT C20000 /* dead code detected */
#elif (configCOMPILER==configCOMPILER_S12_FSL)
#pragma MESSAGE DEFAULT C1404 /* return expected */
#endif
#endif
/*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1
%if defined(vOnPreSleepProcessing)
void %vOnPreSleepProcessing(TickType_t expectedIdleTicks); /* prototype */
%endif
%if defined(vOnPostSleepProcessing)
void %vOnPostSleepProcessing(TickType_t expectedIdleTicks); /* prototype */
%endif
#if (configCOMPILER==configCOMPILER_ARM_GCC) || (configCOMPILER==configCOMPILER_ARM_KEIL)
__attribute__((weak))
#endif
void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime) {
unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements;
TickCounter_t tmp; /* because of how we get the current tick counter */
bool tickISRfired;
uint32_t tickDuration;
#if configSYSTICK_USE_LOW_POWER_TIMER
/* if we wait for the tick interrupt, do not enter low power again below */
if (restoreTickInterval!=0) {
%if defined(vOnPreSleepProcessing)
%vOnPreSleepProcessing(xExpectedIdleTime); /* go into low power mode. Re-enable interrupts as needed! */
%else
/* default wait/sleep code */
%if (CPUfamily = "Kinetis")
__asm volatile("dsb");
__asm volatile("wfi");
__asm volatile("isb");
%elif (CPUfamily = "HCS08") | (CPUfamily = "HC08") | (CPUfamily = "HCS12") | (CPUfamily = "HCS12X")
__asm("cli"); /* re-enable interrupts */
__asm("wait");
%else
#error "unsupported CPU family! vOnPreSleepProcessing() event and go into sleep mode there!"
%endif
%endif
return;
}
#endif
/* Make sure the tick timer reload value does not overflow the counter. */
if(xExpectedIdleTime > xMaximumPossibleSuppressedTicks) {
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the tick timer momentarily. The time the counter is stopped for
* is accounted for as best it can be, but using the tickless mode will
* inevitably result in some tiny drift of the time maintained by the
* kernel with respect to calendar time.
*/
#if configSYSTICK_USE_LOW_POWER_TIMER
/* disabling the LPTMR does reset the timer register! So I need to get the value first, then disable the timer: */
GET_TICK_CURRENT_VAL(&tmp);
DISABLE_TICK_COUNTER();
#else /* using normal timer or SysTick */
DISABLE_TICK_COUNTER();
GET_TICK_CURRENT_VAL(&tmp);
#endif
/* Calculate the reload value required to wait xExpectedIdleTime
* tick periods. This code will execute part way through one
* of the tick periods.
*/
/* -1UL is used because this code will execute part way through one of the tick periods */
#if COUNTS_UP
ulReloadValue = (UL_TIMER_COUNTS_FOR_ONE_TICK*xExpectedIdleTime);
#if configSYSTICK_USE_LOW_POWER_TIMER
if (ulReloadValue > 0) { /* make sure it does not underflow */
ulReloadValue -= 1UL; /* LPTMR: interrupt will happen at match of compare register && increment, thus minus 1 */
}
#endif
if (tmp!=0 && ulReloadValue>=tmp) { /* make sure it does not underflow */
ulReloadValue -= tmp; /* take into account what we already executed in the current tick period */
}
#else
ulReloadValue = tmp+(UL_TIMER_COUNTS_FOR_ONE_TICK*(xExpectedIdleTime-1UL));
#endif
if (ulStoppedTimerCompensation!=0 && ulReloadValue>ulStoppedTimerCompensation) {
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
* method as that will mask interrupts that should exit sleep mode.
*/
TICKLESS_DISABLE_INTERRUPTS();
/* If a context switch is pending or a task is waiting for the scheduler
* to be unsuspended then abandon the low power entry.
*/
if (eTaskConfirmSleepModeStatus()==eAbortSleep) {
/* Must restore the duration before re-enabling the timers */
#if COUNTS_UP
#if configSYSTICK_USE_LOW_POWER_TIMER
tickDuration = UL_TIMER_COUNTS_FOR_ONE_TICK-1UL; /* LPTMR: interrupt will happen at match of compare register && increment, thus minus 1 */
#else
tickDuration = UL_TIMER_COUNTS_FOR_ONE_TICK;
#endif
if (tmp!=0 && tickDuration >= tmp) { /* make sure it does not underflow */
tickDuration -= tmp; /* take into account what we already executed in the current tick period */
}
#else
tickDuration = tmp;
#endif
SET_TICK_DURATION(tickDuration);
ENABLE_TICK_COUNTER(); /* Restart tick timer. */
TICKLESS_ENABLE_INTERRUPTS();
} else {
SET_TICK_DURATION(ulReloadValue); /* Set the new reload value. */
RESET_TICK_COUNTER_VAL(); /* Reset the counter. */
ENABLE_TICK_COUNTER(); /* Restart tick timer. */
TICK_INTERRUPT_FLAG_RESET(); /* reset flag so we know later if it has fired */
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
* set its parameter to 0 to indicate that its implementation contains
* its own wait for interrupt or wait for event instruction, and so wfi
* should not be executed again. However, the original expected idle
* time variable must remain unmodified, so a copy is taken.
*/
/* CPU *HAS TO WAIT* in the sequence below for an interrupt. If vOnPreSleepProcessing() is not used, a default implementation is provided */
%if defined(vOnPreSleepProcessing)
%vOnPreSleepProcessing(xExpectedIdleTime); /* go into low power mode. Re-enable interrupts as needed! */
%else
/* default wait/sleep code */
%if (CPUfamily = "Kinetis")
__asm volatile("dsb");
__asm volatile("wfi");
__asm volatile("isb");
%elif (CPUfamily = "HCS08") | (CPUfamily = "HC08") | (CPUfamily = "HCS12") | (CPUfamily = "HCS12X")
__asm("cli"); /* re-enable interrupts */
__asm("wait");
%else
#error "unsupported CPU family! vOnPreSleepProcessing() event and go into sleep mode there!"
%endif
%endif
/* ----------------------------------------------------------------------------
* Here the CPU *HAS TO BE* low power mode, waiting to wake up by an interrupt
* ----------------------------------------------------------------------------*/
%if defined(vOnPostSleepProcessing)
%vOnPostSleepProcessing(xExpectedIdleTime); /* process post-low power actions */
%endif
/* Stop tick counter. Again, the time the tick counter is stopped for is
* accounted for as best it can be, but using the tickless mode will
* inevitably result in some tiny drift of the time maintained by the
* kernel with respect to calendar time.
*/
tickISRfired = (bool)TICK_INTERRUPT_HAS_FIRED(); /* need to check Interrupt flag here, as might be modified below */
#if configSYSTICK_USE_LOW_POWER_TIMER
/* disabling the LPTMR does reset the timer register! So I need to get the value first, then disable the timer: */
GET_TICK_CURRENT_VAL(&tmp);