Skip to content

Commit d502e29

Browse files
committed
BL: borrow system_init from uf2
works way better in crystalless mode
1 parent 57830a4 commit d502e29

File tree

1 file changed

+93
-224
lines changed

1 file changed

+93
-224
lines changed

bootloaders/zero/board_init.c

Lines changed: 93 additions & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -18,261 +18,130 @@
1818
*/
1919

2020
#include <sam.h>
21+
#include <stdbool.h>
2122
#include "board_definitions.h"
2223

23-
/**
24-
* \brief system_init() configures the needed clocks and according Flash Read Wait States.
25-
* At reset:
26-
* - OSC8M clock source is enabled with a divider by 8 (1MHz).
27-
* - Generic Clock Generator 0 (GCLKMAIN) is using OSC8M as source.
28-
* We need to:
29-
* 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator), will be used as DFLL48M reference.
30-
* 2) Put XOSC32K as source of Generic Clock Generator 1
31-
* 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
32-
* 4) Enable DFLL48M clock
33-
* 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
34-
* 6) Modify PRESCaler value of OSCM to have 8MHz
35-
* 7) Put OSC8M as source for Generic Clock Generator 3
36-
*/
37-
// Constants for Clock generators
38-
#define GENERIC_CLOCK_GENERATOR_MAIN (0u)
39-
#define GENERIC_CLOCK_GENERATOR_XOSC32K (1u)
40-
#define GENERIC_CLOCK_GENERATOR_OSCULP32K (2u) /* Initialized at reset for WDT */
41-
#define GENERIC_CLOCK_GENERATOR_OSC8M (3u)
42-
// Constants for Clock multiplexers
43-
#define GENERIC_CLOCK_MULTIPLEXER_DFLL48M (0u)
44-
45-
void board_init(void)
46-
{
47-
/* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */
48-
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val;
49-
50-
/* Turn on the digital interface clock */
51-
PM->APBAMASK.reg |= PM_APBAMASK_GCLK;
24+
#define SYSCTRL_FUSES_OSC32K_CAL_ADDR (NVMCTRL_OTP4 + 4)
25+
#define SYSCTRL_FUSES_OSC32K_CAL_Pos 6
26+
#define SYSCTRL_FUSES_OSC32K_ADDR SYSCTRL_FUSES_OSC32K_CAL_ADDR
27+
#define SYSCTRL_FUSES_OSC32K_Pos SYSCTRL_FUSES_OSC32K_CAL_Pos
28+
#define SYSCTRL_FUSES_OSC32K_Msk (0x7Fu << SYSCTRL_FUSES_OSC32K_Pos)
5229

53-
#if defined(CRYSTALLESS)
54-
55-
/* ----------------------------------------------------------------------------------------------
56-
* 1) Enable OSC32K clock (Internal 32.768Hz oscillator)
57-
*/
58-
59-
uint32_t calib = (*((uint32_t *) FUSES_OSC32K_CAL_ADDR) & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos;
60-
61-
SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) |
62-
SYSCTRL_OSC32K_STARTUP( 0x6u ) | // cf table 15.10 of product datasheet in chapter 15.8.6
63-
SYSCTRL_OSC32K_EN32K |
64-
SYSCTRL_OSC32K_ENABLE;
65-
66-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC32KRDY) == 0 ); // Wait for oscillator stabilization
67-
68-
#else
69-
70-
/* ----------------------------------------------------------------------------------------------
71-
* 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator)
72-
*/
73-
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */
74-
SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K;
75-
SYSCTRL->XOSC32K.bit.ENABLE = 1; /* separate call, as described in chapter 15.6.3 */
76-
77-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 )
78-
{
79-
/* Wait for oscillator stabilization */
80-
}
81-
82-
#endif
83-
84-
/* Software reset the module to ensure it is re-initialized correctly */
85-
/* Note: Due to synchronization, there is a delay from writing CTRL.SWRST until the reset is complete.
86-
* CTRL.SWRST and STATUS.SYNCBUSY will both be cleared when the reset is complete, as described in chapter 13.8.1
87-
*/
88-
GCLK->CTRL.reg = GCLK_CTRL_SWRST;
89-
90-
while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) )
91-
{
92-
/* Wait for reset to complete */
93-
}
94-
95-
/* ----------------------------------------------------------------------------------------------
96-
* 2) Put XOSC32K as source of Generic Clock Generator 1
97-
*/
98-
GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ); // Generic Clock Generator 1
99-
100-
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
101-
{
102-
/* Wait for synchronization */
103-
}
104-
105-
/* Write Generic Clock Generator 1 configuration */
106-
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) | // Generic Clock Generator 1
107-
#if defined(CRYSTALLESS)
108-
GCLK_GENCTRL_SRC_OSC32K | // Selected source is Internal 32KHz Oscillator
109-
#else
110-
GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator
111-
#endif
112-
// GCLK_GENCTRL_OE | // Output clock to a pin for tests
113-
GCLK_GENCTRL_GENEN;
114-
115-
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
116-
{
117-
/* Wait for synchronization */
118-
}
30+
volatile bool g_interrupt_enabled = true;
11931

120-
/* ----------------------------------------------------------------------------------------------
121-
* 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
122-
*/
123-
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0
124-
GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source
125-
GCLK_CLKCTRL_CLKEN;
126-
127-
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
128-
{
129-
/* Wait for synchronization */
130-
}
131-
132-
/* ----------------------------------------------------------------------------------------------
133-
* 4) Enable DFLL48M clock
134-
*/
135-
136-
/* DFLL Configuration in Closed Loop mode, cf product datasheet chapter 15.6.7.1 - Closed-Loop Operation */
32+
static void gclk_sync(void) {
33+
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
34+
;
35+
}
13736

138-
/* Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905 */
139-
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0;
37+
static void dfll_sync(void) {
38+
while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0)
39+
;
40+
}
14041

141-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
142-
{
143-
/* Wait for synchronization */
144-
}
14542

146-
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value
147-
SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value
148-
SYSCTRL_DFLLMUL_MUL( (VARIANT_MCK/VARIANT_MAINOSC) ); // External 32KHz is the reference
43+
void board_init(void) {
14944

150-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
151-
{
152-
/* Wait for synchronization */
153-
}
45+
NVMCTRL->CTRLB.bit.RWS = 1;
15446

15547
#if defined(CRYSTALLESS)
156-
157-
#define NVM_SW_CALIB_DFLL48M_COARSE_VAL 58
158-
159-
// Turn on DFLL
160-
uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4) + (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32)) >> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32) )
161-
& ((1 << 6) - 1);
48+
/* Configure OSC8M as source for GCLK_GEN 2 */
49+
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2); // Read GENERATOR_ID - GCLK_GEN_2
50+
gclk_sync();
51+
52+
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_SRC_OSC8M_Val | GCLK_GENCTRL_GENEN;
53+
gclk_sync();
54+
55+
// Turn on DFLL with USB correction and sync to internal 8 mhz oscillator
56+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
57+
dfll_sync();
58+
59+
SYSCTRL_DFLLVAL_Type dfllval_conf = {0};
60+
uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4)
61+
+ (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32))
62+
>> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32))
63+
& ((1 << 6) - 1);
16264
if (coarse == 0x3f) {
16365
coarse = 0x1f;
16466
}
165-
// TODO(tannewt): Load this value from memory we've written previously. There
166-
// isn't a value from the Atmel factory.
167-
uint32_t fine = 0x1ff;
67+
dfllval_conf.bit.COARSE = coarse;
68+
// TODO(tannewt): Load this from a well known flash location so that it can be
69+
// calibrated during testing.
70+
dfllval_conf.bit.FINE = 0x1ff;
16871

169-
SYSCTRL->DFLLVAL.bit.COARSE = coarse;
170-
SYSCTRL->DFLLVAL.bit.FINE = fine;
171-
/* Write full configuration to DFLL control register */
17272
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 0x1f / 4 ) | // Coarse step is 31, half of the max value
17373
SYSCTRL_DFLLMUL_FSTEP( 10 ) |
174-
SYSCTRL_DFLLMUL_MUL( (48000) ) ;
175-
74+
48000;
75+
SYSCTRL->DFLLVAL.reg = dfllval_conf.reg;
17676
SYSCTRL->DFLLCTRL.reg = 0;
77+
dfll_sync();
78+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE |
79+
SYSCTRL_DFLLCTRL_CCDIS |
80+
SYSCTRL_DFLLCTRL_USBCRM | /* USB correction */
81+
SYSCTRL_DFLLCTRL_BPLCKC;
82+
dfll_sync();
83+
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ;
84+
dfll_sync();
17785

178-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
179-
{
180-
/* Wait for synchronization */
181-
}
86+
GCLK_CLKCTRL_Type clkctrl={0};
87+
uint16_t temp;
88+
GCLK->CLKCTRL.bit.ID = 2; // GCLK_ID - DFLL48M Reference
89+
temp = GCLK->CLKCTRL.reg;
90+
clkctrl.bit.CLKEN = 1;
91+
clkctrl.bit.WRTLOCK = 0;
92+
clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val;
93+
GCLK->CLKCTRL.reg = (clkctrl.reg | temp);
18294

183-
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE |
184-
SYSCTRL_DFLLCTRL_CCDIS |
185-
SYSCTRL_DFLLCTRL_USBCRM | /* USB correction */
186-
SYSCTRL_DFLLCTRL_BPLCKC;
95+
#else
18796

188-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
189-
{
190-
/* Wait for synchronization */
191-
}
97+
SYSCTRL->XOSC32K.reg =
98+
SYSCTRL_XOSC32K_STARTUP(6) | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K;
99+
SYSCTRL->XOSC32K.bit.ENABLE = 1;
100+
while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0)
101+
;
192102

193-
/* Enable the DFLL */
194-
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ;
103+
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1);
104+
gclk_sync();
195105

196-
#else // has crystal
106+
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN;
107+
gclk_sync();
197108

198-
/* Write full configuration to DFLL control register */
199-
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */
200-
SYSCTRL_DFLLCTRL_WAITLOCK |
201-
SYSCTRL_DFLLCTRL_QLDIS; /* Disable Quick lock */
109+
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(0) | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_CLKEN;
110+
gclk_sync();
202111

203-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
204-
{
205-
/* Wait for synchronization */
206-
}
112+
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0;
113+
dfll_sync();
207114

208-
/* Enable the DFLL */
209-
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE;
115+
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(31) | SYSCTRL_DFLLMUL_FSTEP(511) |
116+
SYSCTRL_DFLLMUL_MUL((CPU_FREQUENCY / (32 * 1024)));
117+
dfll_sync();
210118

211-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 ||
212-
(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 )
213-
{
214-
/* Wait for locks flags */
215-
}
119+
SYSCTRL->DFLLCTRL.reg |=
120+
SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_QLDIS;
121+
dfll_sync();
216122

217-
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
218-
{
219-
/* Wait for synchronization */
220-
}
123+
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE;
221124

222-
#endif
125+
while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 ||
126+
(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0)
127+
;
128+
dfll_sync();
223129

224-
/* ----------------------------------------------------------------------------------------------
225-
* 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
226-
*/
227-
GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ); // Generic Clock Generator 0
130+
#endif
228131

229-
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
230-
{
231-
/* Wait for synchronization */
232-
}
132+
// Configure DFLL48M as source for GCLK_GEN 0
133+
GCLK->GENDIV.reg = GCLK_GENDIV_ID(0);
134+
gclk_sync();
233135

234-
/* Write Generic Clock Generator 0 configuration */
235-
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0
236-
GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz
237-
// GCLK_GENCTRL_OE | // Output clock to a pin for tests
238-
GCLK_GENCTRL_IDC | // Set 50/50 duty cycle
239-
GCLK_GENCTRL_GENEN;
136+
// Add GCLK_GENCTRL_OE below to output GCLK0 on the SWCLK pin.
137+
GCLK->GENCTRL.reg =
138+
GCLK_GENCTRL_ID(0) | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN;
139+
gclk_sync();
240140

241-
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
242-
{
243-
/* Wait for synchronization */
244-
}
141+
SysTick_Config(1000);
245142

246-
#if 0
247-
/* ----------------------------------------------------------------------------------------------
248-
* 6) Modify PRESCaler value of OSC8M to have 8MHz
249-
*/
250-
SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_1_Val;
251-
SYSCTRL->OSC8M.bit.ONDEMAND = 0;
252-
253-
/* ----------------------------------------------------------------------------------------------
254-
* 7) Put OSC8M as source for Generic Clock Generator 3
255-
*/
256-
GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC8M ); // Generic Clock Generator 3
257-
258-
/* Write Generic Clock Generator 3 configuration */
259-
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) | // Generic Clock Generator 3
260-
GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset)
261-
// GCLK_GENCTRL_OE | // Output clock to a pin for tests
262-
GCLK_GENCTRL_GENEN;
263-
264-
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
265-
{
266-
/* Wait for synchronization */
267-
}
268-
#endif //0
269-
270-
/*
271-
* Now that all system clocks are configured, we can set CPU and APBx BUS clocks.
272-
* These values are normally the ones present after Reset.
273-
*/
274-
PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1;
275-
PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val;
276-
PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val;
277-
PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val;
143+
// Uncomment these two lines to output GCLK0 on the SWCLK pin.
144+
// PORT->Group[0].PINCFG[30].bit.PMUXEN = 1;
145+
// Set the port mux mask for odd processor pin numbers, PA30 = 30 is even number, PMUXE = PMUX Even
146+
// PORT->Group[0].PMUX[30 / 2].reg |= PORT_PMUX_PMUXE_H;
278147
}

0 commit comments

Comments
 (0)