C8051F32x firmware infrastructure

Sign in or create your account | Project List | Help

C8051F32x firmware infrastructure Git Source Tree

Root/fw/boot/boot.c

1/*
2 * boot/boot.c - Boot loader setup and main loop
3 *
4 * Written 2008, 2010 by Werner Almesberger
5 * Copyright 2008, 2010 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * This code follows the register read/write sequences from the examples in
15 * SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_Main.c and
16 * SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_ISR.c
17 */
18
19
20#include <stdint.h>
21
22#include "version.h"
23#include "regs.h"
24#include "uart.h"
25#include "usb.h"
26#include "dfu.h"
27
28#include "config.h"
29
30
31#if !defined(CONFIG_DEBUG) && !defined(CONFIG_ERROR) && !defined(CONFIG_PRINTK)
32#define uart_init(x)
33#endif
34
35
36/*
37 * GTA example:
38 *
39
40#define PLATFORM_SETUP \
41    GPIOCN |= WEAKPUD; \
42    I2C_SDA_PULL = 0; \
43    delay();
44
45// Re-enable pull-ups
46// Don't waste power in pull-down
47#define PLATFORM_EXIT \
48    GPIOCN &= ~WEAKPUD; \
49    I2C_SDA_PULL = 1;
50
51#define PLATFORM_TEST \
52    (!I2C_SDA || dfu.state != dfuIDLE)
53 */
54
55#ifndef PLATFORM_SETUP
56#define PLATFORM_SETUP
57#endif
58
59#ifndef PLATFORM_ENTER
60#define PLATFORM_ENTER
61#endif
62
63#ifndef PLATFORM_EXIT
64#define PLATFORM_EXIT
65#endif
66
67
68void run_payload(void)
69{
70    PLATFORM_EXIT;
71
72    /* No interrupts while jumping between worlds */
73    EA = 0;
74
75    /* Restart USB */
76    USB0XCN = 0;
77
78    /*
79     * The USB host must detect a disconnect (pull-ups absent) within 2 and
80     * 2.5 us according to parameter Tddis in table 7-13 on page 186 of the
81     * Universal Serial Bus Specification Revision 2.0.
82     *
83     * If our application calls usb_init really really quickly, we may need
84     * an extra delay here.
85     */
86
87    debug("launching payload\n");
88
89    __asm
90    ljmp PAYLOAD_START
91    __endasm;
92}
93
94
95/* ----- Interrupts -------------------------------------------------------- */
96
97
98/*
99 * The boot loader doesn't use interrupts, so we forward all interrupts to the
100 * payload.
101 *
102 * What we'd really like to do here is to say something like
103 *
104 * void whatever_isr(void) __interrupt(n) __at(PAYLOAD+n*8+1);
105 *
106 * However, sdcc doesn't support such things yet. So we declare the ISR such
107 * that the vector entry gets created, and then we tell the assembler where to
108 * find it.
109 *
110 * Since __asm/__endasm isn't allowed outside a function body, we generate a
111 * dummy function for each assignment. The function is "naked", so that no
112 * actual code is generated for it.
113 */
114
115#define ISR(n) \
116    void isr_nr_##n(void) __interrupt(n); \
117    void isr_dummy_##n(void) __naked \
118    { \
119        __asm \
120        _isr_nr_##n = PAYLOAD_START+n*8+3 \
121        __endasm; \
122    }
123
124
125ISR(0)
126ISR(1)
127ISR(2)
128ISR(3)
129ISR(4)
130ISR(8)
131ISR(15)
132
133
134/* ----- The actual boot loader -------------------------------------------- */
135
136
137static void delay(void)
138{
139    int x;
140
141    for (x = 0; x < 500; x)
142        x++;
143}
144
145
146static void boot_loader(void)
147{
148    OSCICN |= IFCN0 | IFCN1; /* SYSCLK = IOSC/1 (12 MHz) */
149
150#ifdef LOW_SPEED
151
152    CLKSEL = 0x10; /* USBCLK = int/2, SYS_INT_OSC = int */
153
154#else /* LOW_SPEED */
155
156    /*
157     * Clock multiplier enable sequence, section 10.4
158     *
159     * - reset the multiplier
160     * - select the multiplier input source
161     * - enable the multiplier
162     * - delay for 5us
163     * - initialize the multiplier
164     * - poll for multiplier to be ready
165     */
166
167    CLKMUL = 0;
168    CLKMUL |= MULEN;
169    delay();
170    CLKMUL |= MULINIT | MULEN;
171    while (!(CLKMUL & MULRDY));
172    CLKSEL = 0; /* USBCLK = 4*int, SYSCLK = int */
173    CLKSEL = 0x02; /* F326_USB_Main.c does this (sets 24MHz). Why ? */
174
175    uart_init(24);
176
177#endif /* !LOW_SPEED */
178
179    printk("%s #%u\n", build_date, build_number);
180
181    PLATFORM_ENTER;
182
183    dfu_init();
184    usb_init();
185
186#ifdef PLATFORM_TEST
187
188    while (PLATFORM_TEST)
189        usb_poll();
190
191#else /* PLATFORM_TEST */
192
193#define MS_TO_LOOPS(ms) ((uint32_t) (ms)*190)
194
195    {
196        uint32_t loop = 0;
197
198        while (loop != MS_TO_LOOPS(2000)) {
199            usb_poll();
200            if (dfu.state == dfuIDLE)
201                loop++;
202            else
203                loop = 0;
204        }
205    }
206#endif /* !PLATFORM_TEST */
207}
208
209
210void main(void)
211{
212    /*
213     * Any early platform setup, such as turning off the watch dog.
214     */
215    PLATFORM_SETUP;
216
217    /*
218     * VDD monitor enable sequence, section 7.2
219     *
220     * - enable voltage monitor
221     * - wait for monitor to stabilize
222     * - enable VDD monitor reset
223     */
224
225    VDM0CN = VDMEN;
226    while (!(VDM0CN & VDDSTAT));
227    RSTSRC = PORSF;
228
229    /*
230     * @@@ if we don't have VBUS, proceed as follows:
231     * - stay at 3MHz (current < 2mA, so we're fine with GPIO power)
232     * - jump directly to the payload
233     */
234
235    OSCICN |= IFCN0; /* SYSCLK = IOSC/4 (3 MHz) */
236
237    uart_init(3);
238
239    if (REG0CN & VBSTAT)
240        boot_loader();
241    run_payload();
242}
243

Archive Download this file

Branches:
master



interactive