main.c 30.6 KB
Newer Older
1
#include <stdio.h>
2
#include <string.h>
Damien's avatar
Damien committed
3
4
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
5
#include <stm32f4xx_syscfg.h>
6
#include <stm32f4xx_gpio.h>
7
#include <stm32f4xx_exti.h>
8
#include <stm32f4xx_tim.h>
Damien's avatar
Damien committed
9
#include <stm32f4xx_pwr.h>
10
#include <stm32f4xx_rtc.h>
11
#include <stm32f4xx_usart.h>
12
#include <stm32f4xx_rng.h>
13
#include <stm_misc.h>
Damien's avatar
Damien committed
14
15
#include "std.h"

16
#include "misc.h"
17
18
#include "ff.h"
#include "mpconfig.h"
19
#include "qstr.h"
20
21
22
#include "nlr.h"
#include "misc.h"
#include "lexer.h"
23
#include "lexerfatfs.h"
24
25
#include "parse.h"
#include "obj.h"
26
#include "compile.h"
27
28
29
#include "runtime0.h"
#include "runtime.h"
#include "repl.h"
Damien's avatar
Damien committed
30
#include "gc.h"
31
#include "systick.h"
32
#include "led.h"
33
#include "servo.h"
34
#include "lcd.h"
35
#include "storage.h"
36
#include "mma.h"
37
#include "usart.h"
Damien's avatar
Damien committed
38
#include "usb.h"
39
#include "timer.h"
40
#include "audio.h"
41
#include "pybwlan.h"
42
#include "i2c.h"
43
#include "usrsw.h"
mux's avatar
mux committed
44
#include "adc.h"
45
46

int errno;
Damien's avatar
Damien committed
47

Damien's avatar
Damien committed
48
49
extern uint32_t _heap_start;

50
51
static FATFS fatfs0;

52
53
54
55
56
57
58
59
60
61
62
63
void flash_error(int n) {
    for (int i = 0; i < n; i++) {
        led_state(PYB_LED_R1, 1);
        led_state(PYB_LED_R2, 0);
        sys_tick_delay_ms(250);
        led_state(PYB_LED_R1, 0);
        led_state(PYB_LED_R2, 1);
        sys_tick_delay_ms(250);
    }
    led_state(PYB_LED_R2, 0);
}

Damien's avatar
Damien committed
64
void __fatal_error(const char *msg) {
mux's avatar
mux committed
65
#if MICROPY_HW_HAS_LCD
Damien's avatar
Damien committed
66
67
    lcd_print_strn("\nFATAL ERROR:\n", 14);
    lcd_print_strn(msg, strlen(msg));
mux's avatar
mux committed
68
#endif
Damien's avatar
Damien committed
69
    for (;;) {
70
        flash_error(1);
Damien's avatar
Damien committed
71
72
73
    }
}

74
75
static mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
static mp_obj_t pyb_config_main = MP_OBJ_NULL;
76

77
mp_obj_t pyb_source_dir(mp_obj_t source_dir) {
78
79
80
    if (MP_OBJ_IS_STR(source_dir)) {
        pyb_config_source_dir = source_dir;
    }
81
    return mp_const_none;
82
83
}

84
mp_obj_t pyb_main(mp_obj_t main) {
85
86
87
    if (MP_OBJ_IS_STR(main)) {
        pyb_config_main = main;
    }
88
    return mp_const_none;
89
90
91
}

// sync all file systems
92
mp_obj_t pyb_sync(void) {
93
    storage_flush();
94
    return mp_const_none;
95
}
Damien's avatar
Damien committed
96

97
98
99
mp_obj_t pyb_delay(mp_obj_t count) {
    sys_tick_delay_ms(mp_obj_get_int(count));
    return mp_const_none;
Damien's avatar
Damien committed
100
101
}

102
void fatality(void) {
103
104
105
106
107
108
    led_state(PYB_LED_R1, 1);
    led_state(PYB_LED_G1, 1);
    led_state(PYB_LED_R2, 1);
    led_state(PYB_LED_G2, 1);
}

109
static const char fresh_boot_py[] =
110
111
112
113
114
115
116
117
118
119
120
"# boot.py -- run on boot-up\n"
"# can run arbitrary Python, but best to keep it minimal\n"
"\n"
"pyb.source_dir('/src')\n"
"pyb.main('main.py')\n"
"#pyb.usb_usr('VCP')\n"
"#pyb.usb_msd(True, 'dual partition')\n"
"#pyb.flush_cache(False)\n"
"#pyb.error_log('error.txt')\n"
;

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
static const char fresh_main_py[] =
"# main.py -- put your code here!\n"
;

static const char *help_text =
"Welcome to Micro Python!\n\n"
"This is a *very* early version of Micro Python and has minimal functionality.\n\n"
"Specific commands for the board:\n"
"    pyb.info()     -- print some general information\n"
"    pyb.gc()       -- run the garbage collector\n"
"    pyb.delay(<n>) -- wait for n milliseconds\n"
"    pyb.Led(<n>)   -- create Led object for LED n (n=1,2)\n"
"                      Led methods: on(), off()\n"
"    pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n"
"                      Servo methods: angle(<x>)\n"
"    pyb.switch()   -- return True/False if switch pressed or not\n"
"    pyb.accel()    -- get accelerometer values\n"
"    pyb.rand()     -- get a 16-bit random number\n"
139
140
"    pyb.gpio(<port>)           -- get port value (port='a4' for example)\n"
"    pyb.gpio(<port>, <val>)    -- set port value, True or False, 1 or 0\n"
141
142
143
;

// get some help about available functions
144
static mp_obj_t pyb_help(void) {
145
    printf("%s", help_text);
146
    return mp_const_none;
147
148
}

149
// get lots of info about the board
150
static mp_obj_t pyb_info(void) {
151
152
153
154
155
156
    // get and print unique id; 96 bits
    {
        byte *id = (byte*)0x1fff7a10;
        printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]);
    }

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
    // get and print clock speeds
    // SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz
    {
        RCC_ClocksTypeDef rcc_clocks;
        RCC_GetClocksFreq(&rcc_clocks);
        printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n", rcc_clocks.SYSCLK_Frequency, rcc_clocks.HCLK_Frequency, rcc_clocks.PCLK1_Frequency, rcc_clocks.PCLK2_Frequency);
    }

    // to print info about memory
    {
        extern void *_sidata;
        extern void *_sdata;
        extern void *_edata;
        extern void *_sbss;
        extern void *_ebss;
        extern void *_estack;
        extern void *_etext;
        printf("_sidata=%p\n", &_sidata);
        printf("_sdata=%p\n", &_sdata);
        printf("_edata=%p\n", &_edata);
        printf("_sbss=%p\n", &_sbss);
        printf("_ebss=%p\n", &_ebss);
        printf("_estack=%p\n", &_estack);
        printf("_etext=%p\n", &_etext);
        printf("_heap_start=%p\n", &_heap_start);
    }

184
185
186
187
188
189
190
191
192
193
    // GC info
    {
        gc_info_t info;
        gc_info(&info);
        printf("GC:\n");
        printf("  %lu total\n", info.total);
        printf("  %lu : %lu\n", info.used, info.free);
        printf("  1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
    }

194
195
196
197
198
    // free space on flash
    {
        DWORD nclst;
        FATFS *fatfs;
        f_getfree("0:", &nclst, &fatfs);
199
        printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512));
200
    }
201

202
    return mp_const_none;
203
204
}

205
// SD card test
206
static mp_obj_t pyb_sd_test(void) {
207
208
    extern void sdio_init(void);
    sdio_init();
209
    return mp_const_none;
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
static void SYSCLKConfig_STOP(void) {
    /* After wake-up from STOP reconfigure the system clock */
    /* Enable HSE */
    RCC_HSEConfig(RCC_HSE_ON);

    /* Wait till HSE is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET) {
    }

    /* Enable PLL */
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while (RCC_GetSYSCLKSource() != 0x08) {
    }
}

236
static mp_obj_t pyb_stop(void) {
237
238
239
240
241
242
243
244
245
246
247
248
    PWR_EnterSTANDBYMode();
    //PWR_FlashPowerDownCmd(ENABLE); don't know what the logic is with this

    /* Enter Stop Mode */
    PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);

    /* Configures system clock after wake-up from STOP: enable HSE, PLL and select 
     *        PLL as system clock source (HSE and PLL are disabled in STOP mode) */
    SYSCLKConfig_STOP();

    //PWR_FlashPowerDownCmd(DISABLE);

249
    return mp_const_none;
250
251
}

252
static mp_obj_t pyb_standby(void) {
253
    PWR_EnterSTANDBYMode();
254
    return mp_const_none;
255
256
}

Damien's avatar
Damien committed
257
258
259
260
261
262
263
264
265
266
267
268
char *strdup(const char *str) {
    uint32_t len = strlen(str);
    char *s2 = m_new(char, len + 1);
    memcpy(s2, str, len);
    s2[len] = 0;
    return s2;
}

#define READLINE_HIST_SIZE (8)

static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};

269
void stdout_tx_str(const char *str) {
270
271
272
    if (pyb_usart_global_debug != PYB_USART_NONE) {
        usart_tx_str(pyb_usart_global_debug, str);
    }
273
274
275
    usb_vcp_send_str(str);
}

276
int readline(vstr_t *line, const char *prompt) {
277
    stdout_tx_str(prompt);
278
    int len = vstr_len(line);
Damien's avatar
Damien committed
279
280
    int escape = 0;
    int hist_num = 0;
281
    for (;;) {
282
283
284
285
286
        char c;
        for (;;) {
            if (usb_vcp_rx_any() != 0) {
                c = usb_vcp_rx_get();
                break;
287
288
            } else if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) {
                c = usart_rx_char(pyb_usart_global_debug);
289
                break;
290
            }
Damien's avatar
Damien committed
291
            sys_tick_delay_ms(1);
292
293
294
            if (storage_needs_flush()) {
                storage_flush();
            }
295
        }
Damien's avatar
Damien committed
296
297
298
299
        if (escape == 0) {
            if (c == 4 && vstr_len(line) == len) {
                return 0;
            } else if (c == '\r') {
300
                stdout_tx_str("\r\n");
Damien's avatar
Damien committed
301
302
303
304
305
306
307
308
309
310
                for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
                    readline_hist[i] = readline_hist[i - 1];
                }
                readline_hist[0] = strdup(vstr_str(line));
                return 1;
            } else if (c == 27) {
                escape = true;
            } else if (c == 127) {
                if (vstr_len(line) > len) {
                    vstr_cut_tail(line, 1);
311
                    stdout_tx_str("\b \b");
Damien's avatar
Damien committed
312
313
314
                }
            } else if (32 <= c && c <= 126) {
                vstr_add_char(line, c);
315
                stdout_tx_str(line->buf + line->len - 1);
316
            }
Damien's avatar
Damien committed
317
318
319
320
321
322
323
324
325
326
327
328
329
        } else if (escape == 1) {
            if (c == '[') {
                escape = 2;
            } else {
                escape = 0;
            }
        } else if (escape == 2) {
            escape = 0;
            if (c == 'A') {
                // up arrow
                if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) {
                    // erase line
                    for (int i = line->len - len; i > 0; i--) {
330
                        stdout_tx_str("\b \b");
Damien's avatar
Damien committed
331
332
333
334
335
                    }
                    // set line to history
                    line->len = len;
                    vstr_add_str(line, readline_hist[hist_num]);
                    // draw line
336
                    stdout_tx_str(readline_hist[hist_num]);
Damien's avatar
Damien committed
337
338
339
340
341
342
                    // increase hist num
                    hist_num += 1;
                }
            }
        } else {
            escape = 0;
343
        }
Damien's avatar
Damien committed
344
        sys_tick_delay_ms(10);
345
    }
346
347
}

348
void do_repl(void) {
349
    stdout_tx_str("Micro Python build <git hash> on 2/1/2014; PYBv3 with STM32F405RG\r\n");
350
    stdout_tx_str("Type \"help()\" for more information.\r\n");
351
352

    vstr_t line;
353
    vstr_init(&line, 32);
354
355

    for (;;) {
356
357
358
        vstr_reset(&line);
        int ret = readline(&line, ">>> ");
        if (ret == 0) {
359
            // EOF
360
361
362
363
364
            break;
        }

        if (vstr_len(&line) == 0) {
            continue;
365
        }
366

367
        if (mp_repl_is_compound_stmt(vstr_str(&line))) {
368
            for (;;) {
369
370
371
372
373
                vstr_add_char(&line, '\n');
                int len = vstr_len(&line);
                int ret = readline(&line, "... ");
                if (ret == 0 || vstr_len(&line) == len) {
                    // done entering compound statement
374
375
376
377
378
                    break;
                }
            }
        }

379
        mp_lexer_t *lex = mp_lexer_new_from_str_len("<stdin>", vstr_str(&line), vstr_len(&line), 0);
380
381
382
        qstr parse_exc_id;
        const char *parse_exc_msg;
        mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_exc_id, &parse_exc_msg);
383
        qstr source_name = mp_lexer_source_name(lex);
384
385
386
387
388
389
390
391
392

        if (pn == MP_PARSE_NODE_NULL) {
            // parse error
            mp_lexer_show_error_pythonic_prefix(lex);
            printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg);
            mp_lexer_free(lex);
        } else {
            // parse okay
            mp_lexer_free(lex);
393
            mp_obj_t module_fun = mp_compile(pn, source_name, true);
394
395
396
397
398
399
400
401
402
403
            if (module_fun != mp_const_none) {
                nlr_buf_t nlr;
                uint32_t start = sys_tick_counter;
                if (nlr_push(&nlr) == 0) {
                    rt_call_function_0(module_fun);
                    nlr_pop();
                    // optional timing
                    if (0) {
                        uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
                        printf("(took %lu ms)\n", ticks);
404
                    }
405
406
                } else {
                    // uncaught exception
407
                    mp_obj_print_exception((mp_obj_t)nlr.ret_val);
408
409
410
411
                }
            }
        }
    }
412

413
    stdout_tx_str("\r\n");
414
415
416
}

bool do_file(const char *filename) {
Damien George's avatar
Damien George committed
417
    mp_lexer_t *lex = mp_lexer_new_from_file(filename);
418
419
420
421
422
423

    if (lex == NULL) {
        printf("could not open file '%s' for reading\n", filename);
        return false;
    }

424
425
426
    qstr parse_exc_id;
    const char *parse_exc_msg;
    mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_exc_id, &parse_exc_msg);
427
    qstr source_name = mp_lexer_source_name(lex);
428

429
    if (pn == MP_PARSE_NODE_NULL) {
430
431
432
433
        // parse error
        mp_lexer_show_error_pythonic_prefix(lex);
        printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg);
        mp_lexer_free(lex);
434
435
436
        return false;
    }

437
438
    mp_lexer_free(lex);

439
    mp_obj_t module_fun = mp_compile(pn, source_name, false);
440
    if (module_fun == mp_const_none) {
441
442
443
444
445
446
447
448
449
450
        return false;
    }

    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
        rt_call_function_0(module_fun);
        nlr_pop();
        return true;
    } else {
        // uncaught exception
451
        mp_obj_print_exception((mp_obj_t)nlr.ret_val);
452
453
        return false;
    }
454
455
}

456
457
458
459
460
461
#define RAM_START (0x20000000) // fixed for chip
#define HEAP_END  (0x2001c000) // tunable
#define RAM_END   (0x20020000) // fixed for chip

void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end);

462
void gc_collect(void) {
463
    uint32_t start = sys_tick_counter;
Damien's avatar
Damien committed
464
    gc_collect_start();
465
466
467
468
    gc_collect_root((void**)RAM_START, (((uint32_t)&_heap_start) - RAM_START) / 4);
    machine_uint_t regs[10];
    gc_helper_get_regs_and_clean_stack(regs, HEAP_END);
    gc_collect_root((void**)HEAP_END, (RAM_END - HEAP_END) / 4); // will trace regs since they now live in this function on the stack
Damien's avatar
Damien committed
469
    gc_collect_end();
470
    uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
471
472
473
474
475
476
477
478
479
480

    if (0) {
        // print GC info
        gc_info_t info;
        gc_info(&info);
        printf("GC@%lu %lums\n", start, ticks);
        printf(" %lu total\n", info.total);
        printf(" %lu : %lu\n", info.used, info.free);
        printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
    }
481
482
}

483
mp_obj_t pyb_gc(void) {
484
    gc_collect();
485
    return mp_const_none;
486
487
}

488
mp_obj_t pyb_gpio(uint n_args, mp_obj_t *args) {
489
    //assert(1 <= n_args && n_args <= 2);
Damien's avatar
Damien committed
490

491
    const char *pin_name = mp_obj_str_get_str(args[0]);
492
493
494
495
496
497
    GPIO_TypeDef *port;
    switch (pin_name[0]) {
        case 'A': case 'a': port = GPIOA; break;
        case 'B': case 'b': port = GPIOB; break;
        case 'C': case 'c': port = GPIOC; break;
        default: goto pin_error;
498
    }
499
500
501
502
    uint pin_num = 0;
    for (const char *s = pin_name + 1; *s; s++) {
        if (!('0' <= *s && *s <= '9')) {
            goto pin_error;
Damien's avatar
Damien committed
503
        }
504
505
506
507
        pin_num = 10 * pin_num + *s - '0';
    }
    if (!(0 <= pin_num && pin_num <= 15)) {
        goto pin_error;
Damien's avatar
Damien committed
508
    }
509

510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
    if (n_args == 1) {
        // get pin
        if ((port->IDR & (1 << pin_num)) != (uint32_t)Bit_RESET) {
            return MP_OBJ_NEW_SMALL_INT(1);
        } else {
            return MP_OBJ_NEW_SMALL_INT(0);
        }
    } else {
        // set pin
        if (rt_is_true(args[1])) {
            // set pin high
            port->BSRRL = 1 << pin_num;
        } else {
            // set pin low
            port->BSRRH = 1 << pin_num;
        }
        return mp_const_none;
    }
528

529
pin_error:
530
    nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_ValueError, "pin %s does not exist", pin_name));
Damien's avatar
Damien committed
531
532
}

533
534
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio);

535
536
mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
    mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
537
    uint8_t data[4];
538
539
540
541
    data[0] = mp_obj_get_int(items[0]);
    data[1] = mp_obj_get_int(items[1]);
    data[2] = mp_obj_get_int(items[2]);
    data[3] = mp_obj_get_int(items[3]);
542
    usb_hid_send_report(data);
543
    return mp_const_none;
544
545
}

546
static void rtc_init(void) {
547
    uint32_t rtc_clksrc;
548
    uint32_t timeout = 1000000;
549

550
551
552
553
554
555
556
557
558
559
    /* Enable the PWR clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

    /* Allow access to RTC */
    PWR_BackupAccessCmd(ENABLE);

    /* Enable the LSE OSC */
    RCC_LSEConfig(RCC_LSE_ON);

    /* Wait till LSE is ready */
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
    while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) && (--timeout > 0)) {
    }

    /* If LSE timed out, use LSI instead */
    if (timeout == 0) {
        /* Enable the LSI OSC */
        RCC_LSICmd(ENABLE);

        /* Wait till LSI is ready */
        while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) {
        }

        /* Use LSI as the RTC Clock Source */
        rtc_clksrc = RCC_RTCCLKSource_LSI;
    } else {
        /* Use LSE as the RTC Clock Source */
        rtc_clksrc = RCC_RTCCLKSource_LSE;
577
578
579
    }

    /* Select the RTC Clock Source */
580
581
582
    RCC_RTCCLKConfig(rtc_clksrc);

    /* Note: LSI is around (32KHz), these dividers should work either way */
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
    /* ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
    uint32_t uwSynchPrediv = 0xFF;
    uint32_t uwAsynchPrediv = 0x7F;

    /* Enable the RTC Clock */
    RCC_RTCCLKCmd(ENABLE);

    /* Wait for RTC APB registers synchronisation */
    RTC_WaitForSynchro();

    /* Configure the RTC data register and RTC prescaler */
    RTC_InitTypeDef RTC_InitStructure;
    RTC_InitStructure.RTC_AsynchPrediv = uwAsynchPrediv;
    RTC_InitStructure.RTC_SynchPrediv = uwSynchPrediv;
    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
    RTC_Init(&RTC_InitStructure);

    // Set the date (BCD)
    RTC_DateTypeDef RTC_DateStructure;
    RTC_DateStructure.RTC_Year = 0x13;
    RTC_DateStructure.RTC_Month = RTC_Month_October;
    RTC_DateStructure.RTC_Date = 0x26;
    RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Saturday;
    RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);

    // Set the time (BCD)
    RTC_TimeTypeDef RTC_TimeStructure;
    RTC_TimeStructure.RTC_H12     = RTC_H12_AM;
    RTC_TimeStructure.RTC_Hours   = 0x01;
    RTC_TimeStructure.RTC_Minutes = 0x53;
    RTC_TimeStructure.RTC_Seconds = 0x00;
    RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);

    // Indicator for the RTC configuration
    //RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
}

620
mp_obj_t pyb_rtc_read(void) {
621
622
623
    RTC_TimeTypeDef RTC_TimeStructure;
    RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
    printf("%02d:%02d:%02d\n", RTC_TimeStructure.RTC_Hours, RTC_TimeStructure.RTC_Minutes, RTC_TimeStructure.RTC_Seconds);
624
    return mp_const_none;
625
626
}

627
628
629
630
631
typedef struct _pyb_file_obj_t {
    mp_obj_base_t base;
    FIL fp;
} pyb_file_obj_t;

632
void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
633
    printf("<file %p>", self_in);
Damien's avatar
Damien committed
634
635
}

636
637
638
mp_obj_t file_obj_read(mp_obj_t self_in, mp_obj_t arg) {
    pyb_file_obj_t *self = self_in;
    int n = mp_obj_get_int(arg);
639
    byte *buf = m_new(byte, n);
Damien's avatar
Damien committed
640
    UINT n_out;
641
    f_read(&self->fp, buf, n, &n_out);
642
    return mp_obj_new_str(buf, n_out, false);
Damien's avatar
Damien committed
643
644
}

645
646
mp_obj_t file_obj_write(mp_obj_t self_in, mp_obj_t arg) {
    pyb_file_obj_t *self = self_in;
647
648
    uint l;
    const byte *s = mp_obj_str_get_data(arg, &l);
Damien's avatar
Damien committed
649
    UINT n_out;
650
    FRESULT res = f_write(&self->fp, s, l, &n_out);
Damien's avatar
Damien committed
651
652
    if (res != FR_OK) {
        printf("File error: could not write to file; error code %d\n", res);
653
654
    } else if (n_out != l) {
        printf("File error: could not write all data to file; wrote %d / %d bytes\n", n_out, l);
Damien's avatar
Damien committed
655
    }
656
    return mp_const_none;
Damien's avatar
Damien committed
657
658
}

659
660
661
662
mp_obj_t file_obj_close(mp_obj_t self_in) {
    pyb_file_obj_t *self = self_in;
    f_close(&self->fp);
    return mp_const_none;
Damien's avatar
Damien committed
663
664
}

665
666
667
668
static MP_DEFINE_CONST_FUN_OBJ_2(file_obj_read_obj, file_obj_read);
static MP_DEFINE_CONST_FUN_OBJ_2(file_obj_write_obj, file_obj_write);
static MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close);

Damien's avatar
Damien committed
669
// TODO gc hook to close the file if not already closed
670

671
672
673
674
675
676
677
static const mp_method_t file_methods[] = {
    { "read", &file_obj_read_obj },
    { "write", &file_obj_write_obj },
    { "close", &file_obj_close_obj },
    {NULL, NULL},
};

678
679
static const mp_obj_type_t file_obj_type = {
    { &mp_const_type },
Damien's avatar
Damien committed
680
    "File",
681
682
    .print = file_obj_print,
    .methods = file_methods,
Damien's avatar
Damien committed
683
684
};

685
mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) {
686
687
    const char *filename = mp_obj_str_get_str(o_filename);
    const char *mode = mp_obj_str_get_str(o_mode);
688
689
    pyb_file_obj_t *self = m_new_obj(pyb_file_obj_t);
    self->base.type = &file_obj_type;
Damien's avatar
Damien committed
690
691
    if (mode[0] == 'r') {
        // open for reading
692
        FRESULT res = f_open(&self->fp, filename, FA_READ);
Damien's avatar
Damien committed
693
694
        if (res != FR_OK) {
            printf("FileNotFoundError: [Errno 2] No such file or directory: '%s'\n", filename);
695
            return mp_const_none;
Damien's avatar
Damien committed
696
697
698
        }
    } else if (mode[0] == 'w') {
        // open for writing, truncate the file first
699
        FRESULT res = f_open(&self->fp, filename, FA_WRITE | FA_CREATE_ALWAYS);
Damien's avatar
Damien committed
700
701
        if (res != FR_OK) {
            printf("?FileError: could not create file: '%s'\n", filename);
702
            return mp_const_none;
Damien's avatar
Damien committed
703
704
705
        }
    } else {
        printf("ValueError: invalid mode: '%s'\n", mode);
706
        return mp_const_none;
Damien's avatar
Damien committed
707
    }
708
    return self;
Damien's avatar
Damien committed
709
710
}

711
712
mp_obj_t pyb_rng_get(void) {
    return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
713
714
}

715
int main(void) {
716
    // TODO disable JTAG
Damien's avatar
Damien committed
717

718
719
720
    // update the SystemCoreClock variable
    SystemCoreClockUpdate();

721
722
723
724
    // set interrupt priority config to use all 4 bits for pre-empting
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

    // enable the CCM RAM and the GPIO's
725
726
727
728
729
    RCC->AHB1ENR |= RCC_AHB1ENR_CCMDATARAMEN | RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN
#if defined(STM32F4DISC)
        | RCC_AHB1ENR_GPIODEN
#endif
        ;
730

731
    // configure SDIO pins to be high to start with (apparently makes it more robust)
mux's avatar
mux committed
732
733
734
735
736
737
738
739
740
741
742
743
744
#if MICROPY_HW_HAS_SDCARD
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    // Configure PD.02 CMD line
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
#endif
745

746
747
    // basic sub-system init
    sys_tick_init();
Damien's avatar
Damien committed
748
    led_init();
mux's avatar
mux committed
749
750

#if MICROPY_HW_ENABLE_RTC
751
    rtc_init();
mux's avatar
mux committed
752
#endif
753
754
755
756
757

    // turn on LED to indicate bootup
    led_state(PYB_LED_G1, 1);

    // more sub-system init
mux's avatar
mux committed
758
#if MICROPY_HW_HAS_SWITCH
759
    switch_init();
mux's avatar
mux committed
760
#endif
761
    storage_init();
762

763
    // uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP
764
    //pyb_usart_global_debug = PYB_USART_3;
765
    //usart_init(pyb_usart_global_debug, 115200);
Damien's avatar
Damien committed
766

767
768
    int first_soft_reset = true;

769
770
soft_reset:

Damien's avatar
Damien committed
771
    // GC init
772
    gc_init(&_heap_start, (void*)HEAP_END);
Damien's avatar
Damien committed
773

774
    // Micro Python init
775
776
    qstr_init();
    rt_init();
777

mux's avatar
mux committed
778
#if MICROPY_HW_HAS_LCD
779
    // LCD init
mux's avatar
mux committed
780
781
    lcd_init(); /* disabled while servos on PA0 PA1 */
#endif
782

mux's avatar
mux committed
783
#if MICROPY_HW_ENABLE_SERVO
784
785
    // servo
    servo_init();
mux's avatar
mux committed
786
#endif
787

mux's avatar
mux committed
788
#if MICROPY_HW_ENABLE_AUDIO
789
    // audio
mux's avatar
mux committed
790
791
    audio_init();
#endif
792

mux's avatar
mux committed
793
#if MICROPY_HW_ENABLE_TIMER
794
795
    // timer
    timer_init();
mux's avatar
mux committed
796
#endif
797

mux's avatar
mux committed
798
#if MICROPY_HW_ENABLE_RNG
799
    // RNG
mux's avatar
mux committed
800
801
802
    RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
    RNG_Cmd(ENABLE);
#endif
803

804
    // add some functions to the python namespace
805
    {
806
807
808
809
        rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help));

        mp_obj_t m = mp_obj_new_module(MP_QSTR_pyb);
        rt_store_attr(m, MP_QSTR_info, rt_make_function_n(0, pyb_info));
mux's avatar
mux committed
810
#if MICROPY_HW_HAS_SDCARD
811
        rt_store_attr(m, MP_QSTR_sd_test, rt_make_function_n(0, pyb_sd_test));
mux's avatar
mux committed
812
#endif
813
814
815
816
817
818
819
        rt_store_attr(m, MP_QSTR_stop, rt_make_function_n(0, pyb_stop));
        rt_store_attr(m, MP_QSTR_standby, rt_make_function_n(0, pyb_standby));
        rt_store_attr(m, MP_QSTR_source_dir, rt_make_function_n(1, pyb_source_dir));
        rt_store_attr(m, MP_QSTR_main, rt_make_function_n(1, pyb_main));
        rt_store_attr(m, MP_QSTR_sync, rt_make_function_n(0, pyb_sync));
        rt_store_attr(m, MP_QSTR_gc, rt_make_function_n(0, pyb_gc));
        rt_store_attr(m, MP_QSTR_delay, rt_make_function_n(1, pyb_delay));
mux's avatar
mux committed
820
#if MICROPY_HW_HAS_SWITCH
821
        rt_store_attr(m, MP_QSTR_switch, (mp_obj_t)&pyb_switch_obj);
mux's avatar
mux committed
822
823
#endif
#if MICROPY_HW_ENABLE_SERVO
824
        rt_store_attr(m, MP_QSTR_servo, rt_make_function_n(2, pyb_servo_set));
mux's avatar
mux committed
825
#endif
826
        rt_store_attr(m, MP_QSTR_pwm, rt_make_function_n(2, pyb_pwm_set));
mux's avatar
mux committed
827
#if MICROPY_HW_HAS_MMA7660
828
829
830
        rt_store_attr(m, MP_QSTR_accel, (mp_obj_t)&pyb_mma_read_obj);
        rt_store_attr(m, MP_QSTR_mma_read, (mp_obj_t)&pyb_mma_read_all_obj);
        rt_store_attr(m, MP_QSTR_mma_mode, (mp_obj_t)&pyb_mma_write_mode_obj);
831
#endif
832
        rt_store_attr(m, MP_QSTR_hid, rt_make_function_n(1, pyb_hid_send_report));
mux's avatar
mux committed
833
#if MICROPY_HW_HAS_RTC
834
        rt_store_attr(m, MP_QSTR_time, rt_make_function_n(0, pyb_rtc_read));
mux's avatar
mux committed
835
836
#endif
#if MICROPY_HW_ENABLE_RNG
837
        rt_store_attr(m, MP_QSTR_rand, rt_make_function_n(0, pyb_rng_get));
mux's avatar
mux committed
838
#endif
839
        rt_store_attr(m, MP_QSTR_Led, (mp_obj_t)&pyb_Led_obj);
mux's avatar
mux committed
840
#if MICROPY_HW_ENABLE_SERVO
841
        rt_store_attr(m, MP_QSTR_Servo, rt_make_function_n(1, pyb_Servo));
mux's avatar
mux committed
842
#endif
843
844
845
846
847
848
849
        rt_store_attr(m, MP_QSTR_I2C, rt_make_function_n(2, pyb_I2C));
        rt_store_attr(m, MP_QSTR_gpio, (mp_obj_t)&pyb_gpio_obj);
        rt_store_attr(m, MP_QSTR_Usart, rt_make_function_n(2, pyb_Usart));
        rt_store_attr(m, MP_QSTR_ADC, rt_make_function_n(1, pyb_ADC));
        rt_store_name(MP_QSTR_pyb, m);

        rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open));
850
    }
851

mux's avatar
mux committed
852
#if MICROPY_HW_HAS_LCD
853
854
    // print a message to the LCD
    lcd_print_str(" micro py board\n");
mux's avatar
mux committed
855
#endif
Damien's avatar
Damien committed
856

857
858
    // check if user switch held (initiates reset of filesystem)
    bool reset_filesystem = false;
mux's avatar
mux committed
859
#if MICROPY_HW_HAS_SWITCH
860
    if (switch_get()) {
861
862
        reset_filesystem = true;
        for (int i = 0; i < 50; i++) {
863
            if (!switch_get()) {
864
865
866
867
868
869
                reset_filesystem = false;
                break;
            }
            sys_tick_delay_ms(10);
        }
    }
mux's avatar
mux committed
870
#endif
871
872
873
874
    // local filesystem init
    {
        // try to mount the flash
        FRESULT res = f_mount(&fatfs0, "0:", 1);
875
        if (!reset_filesystem && res == FR_OK) {
876
            // mount sucessful
877
        } else if (reset_filesystem || res == FR_NO_FILESYSTEM) {
878
            // no filesystem, so create a fresh one
879
            // TODO doesn't seem to work correctly when reset_filesystem is true...
880
881
882
883
884
885
886
887
888
889
890
891

            // LED on to indicate creation of LFS
            led_state(PYB_LED_R2, 1);
            uint32_t stc = sys_tick_counter;

            res = f_mkfs("0:", 0, 0);
            if (res == FR_OK) {
                // success creating fresh LFS
            } else {
                __fatal_error("could not create LFS");
            }

892
893
894
895
896
897
898
899
900
901
902
903
            // create src directory
            res = f_mkdir("0:/src");
            // ignore result from mkdir

            // create empty main.py
            FIL fp;
            f_open(&fp, "0:/src/main.py", FA_WRITE | FA_CREATE_ALWAYS);
            UINT n;
            f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n);
            // TODO check we could write n bytes
            f_close(&fp);

904
905
            // keep LED on for at least 200ms
            sys_tick_wait_at_least(stc, 200);
906
907
908
909
            led_state(PYB_LED_R2, 0);
        } else {
            __fatal_error("could not access LFS");
        }
Damien's avatar
Damien committed
910
911
    }

912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
    // make sure we have a /boot.py
    {
        FILINFO fno;
        FRESULT res = f_stat("0:/boot.py", &fno);
        if (res == FR_OK) {
            if (fno.fattrib & AM_DIR) {
                // exists as a directory
                // TODO handle this case
                // see http://elm-chan.org/fsw/ff/img/app2.c for a "rm -rf" implementation
            } else {
                // exists as a file, good!
            }
        } else {
            // doesn't exist, create fresh file

            // LED on to indicate creation of boot.py
            led_state(PYB_LED_R2, 1);
            uint32_t stc = sys_tick_counter;

            FIL fp;
            f_open(&fp, "0:/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
            UINT n;
934
            f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
935
936
937
            // TODO check we could write n bytes
            f_close(&fp);

938
939
            // keep LED on for at least 200ms
            sys_tick_wait_at_least(stc, 200);
940
941
942
943
            led_state(PYB_LED_R2, 0);
        }
    }

944
945
946
947
948
    // run /boot.py
    if (!do_file("0:/boot.py")) {
        flash_error(4);
    }

949
950
951
    // USB
    usb_init();

952
953
    // USB host; not working!
    //pyb_usbh_init();
954
955
    //rt_store_name(qstr_from_str("u_p"), rt_make_function_n(0, pyb_usbh_process));
    //rt_store_name(qstr_from_str("u_c"), rt_make_function_n(0, pyb_usbh_connect));
956

957
    if (first_soft_reset) {
mux's avatar
mux committed
958
#if MICROPY_HW_HAS_MMA7660
959
        // MMA: init and reset address to zero
Damien's avatar
Damien committed
960
        mma_init();
961
#endif
Damien's avatar
Damien committed
962
963
    }

964
965
    // turn boot-up LED off
    led_state(PYB_LED_G1, 0);
966

967
968
969
970
    // run main script
    {
        vstr_t *vstr = vstr_new();
        vstr_add_str(vstr, "0:/");
971
        if (pyb_config_source_dir == MP_OBJ_NULL) {
972
973
            vstr_add_str(vstr, "src");
        } else {
974
            vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_source_dir));
975
976
        }
        vstr_add_char(vstr, '/');
977
        if (pyb_config_main == MP_OBJ_NULL) {
978
979
            vstr_add_str(vstr, "main.py");
        } else {
980
            vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main));
981
982
983
        }
        if (!do_file(vstr_str(vstr))) {
            flash_error(3);
984
        }
985
        vstr_free(vstr);
986
987
    }

Damien's avatar
Damien committed
988

mux's avatar
mux committed
989
#if MICROPY_HW_HAS_MMA7660
990
991
992
993
994
995
996
997
    // HID example
    if (0) {
        uint8_t data[4];
        data[0] = 0;
        data[1] = 1;
        data[2] = -2;
        data[3] = 0;
        for (;;) {
mux's avatar
mux committed
998
        #if MICROPY_HW_HAS_SWITCH
999
            if (switch_get()) {
1000
1001
1002
1003
                data[0] = 0x01; // 0x04 is middle, 0x02 is right
            } else {
                data[0] = 0x00;
            }
mux's avatar
mux committed
1004
1005
1006
        #else
            data[0] = 0x00;
        #endif
1007
            mma_start(0x4c /* MMA_ADDR */, 1);
1008
            mma_send_byte(0);
1009
            mma_restart(0x4c /* MMA_ADDR */, 0);
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
            for (int i = 0; i <= 1; i++) {
                int v = mma_read_ack() & 0x3f;
                if (v & 0x20) {
                    v |= ~0x1f;
                }
                data[1 + i] = v;
            }
            mma_read_nack();
            usb_hid_send_report(data);
            sys_tick_delay_ms(15);
        }
    }
1022
#endif
1023

mux's avatar
mux committed
1024
#if MICROPY_HW_HAS_WLAN
1025
    // wifi
mux's avatar
mux committed
1026
1027
1028
    pyb_wlan_init();
    pyb_wlan_start();
#endif
1029

1030
1031
    do_repl();

1032
1033
1034
1035
    printf("PYB: sync filesystems\n");
    pyb_sync();

    printf("PYB: soft reboot\n");
1036
1037

    first_soft_reset = false;
1038
    goto soft_reset;
Damien's avatar
Damien committed
1039