-
Notifications
You must be signed in to change notification settings - Fork 4
/
system.c
277 lines (243 loc) · 11.9 KB
/
system.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
/*******************************************************************************
Copyright 2016 Microchip Technology Inc. (www.microchip.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
To request to license the code under the MLA license (www.microchip.com/mla_license),
please contact mla_licensing@microchip.com
*******************************************************************************/
#include <xc.h>
#include "system.h"
#include "usb.h"
#include "configuration_bits.h"
/*********************************************************************
* Function: void SYSTEM_Initialize( SYSTEM_STATE state )
*
* Overview: Initializes the system.
*
* PreCondition: None
*
* Input: SYSTEM_STATE - the state to initialize the system into
*
* Output: None
*
********************************************************************/
void SYSTEM_Initialize( SYSTEM_STATE state )
{
switch(state)
{
case SYSTEM_STATE_USB_START:
//In this devices family of USB microcontrollers, the PLL will not power up and be enabled
//by default, even if a PLL enabled oscillator configuration is selected (such as HS+PLL).
//This allows the device to power up at a lower initial operating frequency, which can be
//advantageous when powered from a source which is not gauranteed to be adequate for 48MHz
//operation. On these devices, user firmware needs to manually set the OSCTUNE<PLLEN> bit to
//power up the PLL.
{
unsigned int pll_startup_counter = 600;
OSCTUNEbits.PLLEN = 1; //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
while(pll_startup_counter--);
}
//Device switches over automatically to PLL output after PLL is locked and ready.
//LED_Enable(LED_USB_DEVICE_STATE);
//LED_Enable(LED_USB_DEVICE_HID_CUSTOM);
//BUTTON_Enable(BUTTON_USB_DEVICE_HID_CUSTOM);
//ADC_SetConfiguration(ADC_CONFIGURATION_DEFAULT);
//ADC_Enable(ADC_CHANNEL_POTENTIOMETER);
break;
case SYSTEM_STATE_USB_SUSPEND:
//Should also configure all other I/O pins for lowest power consumption.
//Typically this is done by driving unused I/O pins as outputs and driving them high or low.
//In this example, this is not done however, in case the user is expecting the I/O pins
//to remain tri-state and has hooked something up to them.
//Leaving the I/O pins floating will waste power and should not be done in a
//real application.
//Sleep on sleep, 125kHz selected as microcontroller clock source
break;
case SYSTEM_STATE_USB_RESUME:
OSCCON = 0x70; //Primary clock source selected.
//Adding a software start up delay will ensure
//that the primary oscillator and PLL are running before executing any other
//code. If the PLL isn't being used, (ex: primary osc = 48MHz externally applied EC)
//then this code adds a small unnecessary delay, but it is harmless to execute anyway.
{
unsigned int pll_startup_counter = 800; //Long delay at 31kHz, but ~0.8ms at 48MHz
while(pll_startup_counter--); //Clock will switch over while executing this delay loop
}
break;
}
}
/*********************************************************************
* Function: bool SYSTEM_UserSelfWriteUnlockVerification(void)
*
* Overview: Self erase/writes to flash memory could potentially corrupt the
* firmware of the application, if the unlock sequence is ever executed
* unintentionally, or if the table pointer is pointing to an invalid
* range (not inside the MSD volume range). Therefore, in order to ensure
* a fully reliable design that is suitable for mass production, it is strongly
* recommended to implement several robustness checks prior to actually
* performing any self erase/program unlock sequence. See additional inline
* code comments.
*
* PreCondition: None
*
* Input: None
*
* Output: true - self write allowed, false - self write not allowed.
*
********************************************************************/
bool SYSTEM_UserSelfWriteUnlockVerification(void)
{
//Should verify that the voltage on Vdd/Vddcore is high enough to meet
//the datasheet minimum voltage vs. frequency graph for the device.
//If the microcontroller is "overclocked" (ex: by running at maximum rated
//frequency, but then not suppling enough voltage to meet the datasheet
//voltage vs. frequency graph), errant code execution could occur. It is
//therefore strongly recommended to check the voltage prior to performing a
//flash self erase/write unlock sequence. If the voltage is too low to meet
//the voltage vs. frequency graph in the datasheet, the firmware should not
//initiate a self erase/program operation, and instead it should either:
//1. Clock switch to a lower frequency that does meet the voltage/frequency graph. Or,
//2. Put the microcontroller to Sleep mode.
//The method used to measure Vdd and/or Vddcore will depend upon the
//microcontroller model and the module features available in the device, but
//several options are available on many of the microcontrollers, ex:
//1. HLVD module
//2. WDTCON<LVDSTAT> indicator bit
//3. Perform ADC operation, with the VBG channel selected, using Vdd/Vss as
// references to the ADC. Then perform math operations to calculate the Vdd.
// On some micros, the ADC can also measure the Vddcore voltage, allowing
// the firmware to calculate the absolute Vddcore voltage, if it has already
// calculated and knows the ADC reference voltage.
//4. Use integrated general purpose comparator(s) to sense Vdd/Vddcore voltage
// is above proper threshold.
//5. If the micrcontroller implements a user adjustable BOR circuit, enable
// it and set the trip point high enough to avoid overclocking altogether.
//Example pseudo code. Exact implementation will be application specific.
//Please implement appropriate code that best meets your application requirements.
//if(GetVddcoreVoltage() < MIN_ALLOWED_VOLTAGE)
//{
// ClockSwitchToSafeFrequencyForGivenVoltage(); //Or even better, go to sleep mode.
// return false;
//}
//Should also verify the TBLPTR is pointing to a valid range (part of the MSD
//volume, and not a part of the application firmware space).
//Example code for PIC18 (commented out since the actual address range is
//application specific):
//if((TBLPTR > MSD_VOLUME_MAX_ADDRESS) || (TBLPTR < MSD_VOLUME_START_ADDRESS))
//{
// return false;
//}
return true;
}
#if defined(__XC8)
void interrupt SYS_InterruptHigh(void)
{
#if defined(USB_INTERRUPT)
USBDeviceTasks();
#endif
//User-defined ISR
tmr_isr();
}
#else
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
//On PIC18 devices, addresses 0x00, 0x08, and 0x18 are used for
//the reset, high priority interrupt, and low priority interrupt
//vectors. However, the current Microchip USB bootloader
//examples are intended to occupy addresses 0x00-0x7FF or
//0x00-0xFFF depending on which bootloader is used. Therefore,
//the bootloader code remaps these vectors to new locations
//as indicated below. This remapping is only necessary if you
//wish to program the hex file generated from this project with
//the USB bootloader. If no bootloader is used, edit the
//usb_config.h file and comment out the following defines:
//#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER
//#define PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
#define REMAPPED_RESET_VECTOR_ADDRESS 0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018
#elif defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
#define REMAPPED_RESET_VECTOR_ADDRESS 0x800
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x808
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x818
#else
#define REMAPPED_RESET_VECTOR_ADDRESS 0x00
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x08
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x18
#endif
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
extern void _startup (void); // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
_asm goto _startup _endasm
}
#endif
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void)
{
_asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void Remapped_Low_ISR (void)
{
_asm goto YourLowPriorityISRCode _endasm
}
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
//Note: If this project is built while one of the bootloaders has
//been defined, but then the output hex file is not programmed with
//the bootloader, addresses 0x08 and 0x18 would end up programmed with 0xFFFF.
//As a result, if an actual interrupt was enabled and occured, the PC would jump
//to 0x08 (or 0x18) and would begin executing "0xFFFF" (unprogrammed space). This
//executes as nop instructions, but the PC would eventually reach the REMAPPED_RESET_VECTOR_ADDRESS
//(0x1000 or 0x800, depending upon bootloader), and would execute the "goto _startup". This
//would effective reset the application.
//To fix this situation, we should always deliberately place a
//"goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS" at address 0x08, and a
//"goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS" at address 0x18. When the output
//hex file of this project is programmed with the bootloader, these sections do not
//get bootloaded (as they overlap the bootloader space). If the output hex file is not
//programmed using the bootloader, then the below goto instructions do get programmed,
//and the hex file still works like normal. The below section is only required to fix this
//scenario.
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void)
{
_asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void)
{
_asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
#endif //end of "#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER)"
#pragma code
//These are your actual interrupt handling routines.
#pragma interrupt YourHighPriorityISRCode
void YourHighPriorityISRCode()
{
//Check which interrupt flag caused the interrupt.
//Service the interrupt
//Clear the interrupt flag
//Etc.
#if defined(USB_INTERRUPT)
USBDeviceTasks();
#endif
} //This return will be a "retfie fast", since this is in a #pragma interrupt section
#pragma interruptlow YourLowPriorityISRCode
void YourLowPriorityISRCode()
{
//Check which interrupt flag caused the interrupt.
//Service the interrupt
//Clear the interrupt flag
//Etc.
} //This return will be a "retfie", since this is in a #pragma interruptlow section
#endif