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

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

int errno;
Damien's avatar
Damien committed
45

Damien's avatar
Damien committed
46
47
extern uint32_t _heap_start;

48
49
static FATFS fatfs0;

50
51
52
53
54
55
56
57
58
59
60
61
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);
}

62
static void impl02_c_version(void) {
Damien's avatar
Damien committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    int x = 0;
    while (x < 400) {
        int y = 0;
        while (y < 400) {
            volatile int z = 0;
            while (z < 400) {
                z = z + 1;
            }
            y = y + 1;
        }
        x = x + 1;
    }
}

void __fatal_error(const char *msg) {
    lcd_print_strn("\nFATAL ERROR:\n", 14);
    lcd_print_strn(msg, strlen(msg));
    for (;;) {
81
        flash_error(1);
Damien's avatar
Damien committed
82
83
84
    }
}

85
86
87
static qstr pyb_config_source_dir = 0;
static qstr pyb_config_main = 0;

88
89
90
mp_obj_t pyb_source_dir(mp_obj_t source_dir) {
    pyb_config_source_dir = mp_obj_get_qstr(source_dir);
    return mp_const_none;
91
92
}

93
94
95
mp_obj_t pyb_main(mp_obj_t main) {
    pyb_config_main = mp_obj_get_qstr(main);
    return mp_const_none;
96
97
98
}

// sync all file systems
99
mp_obj_t pyb_sync(void) {
100
    storage_flush();
101
    return mp_const_none;
102
}
Damien's avatar
Damien committed
103

104
105
106
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
107
108
}

109
mp_obj_t pyb_led(mp_obj_t state) {
110
    led_state(PYB_LED_G1, rt_is_true(state));
Damien's avatar
Damien committed
111
112
113
    return state;
}

114
/*
115
116
117
118
119
120
void g(uint i) {
    printf("g:%d\n", i);
    if (i & 1) {
        nlr_jump((void*)(42 + i));
    }
}
121
void f(void) {
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
    nlr_buf_t nlr;
    int i;
    for (i = 0; i < 4; i++) {
        printf("f:loop:%d:%p\n", i, &nlr);
        if (nlr_push(&nlr) == 0) {
            // normal
            //printf("a:%p:%p %p %p %u\n", &nlr, nlr.ip, nlr.sp, nlr.prev, nlr.ret_val);
            g(i);
            printf("f:lp:%d:nrm\n", i);
            nlr_pop();
        } else {
            // nlr
            //printf("b:%p:%p %p %p %u\n", &nlr, nlr.ip, nlr.sp, nlr.prev, nlr.ret_val);
            printf("f:lp:%d:nlr:%d\n", i, (int)nlr.ret_val);
        }
    }
}
139
void nlr_test(void) {
140
141
    f(1);
}
142
143
*/

144
void fatality(void) {
145
146
147
148
149
150
    led_state(PYB_LED_R1, 1);
    led_state(PYB_LED_G1, 1);
    led_state(PYB_LED_R2, 1);
    led_state(PYB_LED_G2, 1);
}

151
static const char fresh_boot_py[] =
152
153
154
155
156
157
158
159
160
161
162
"# 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"
;

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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"
;

// get some help about available functions
184
static mp_obj_t pyb_help(void) {
185
    printf("%s", help_text);
186
    return mp_const_none;
187
188
}

189
// get lots of info about the board
190
static mp_obj_t pyb_info(void) {
191
192
193
194
195
196
    // 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]);
    }

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
    // 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);
    }

224
225
226
227
228
229
230
231
232
233
    // 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);
    }

234
235
236
237
238
    // free space on flash
    {
        DWORD nclst;
        FATFS *fatfs;
        f_getfree("0:", &nclst, &fatfs);
239
        printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512));
240
    }
241

242
    return mp_const_none;
243
244
}

245
// SD card test
246
static mp_obj_t pyb_sd_test(void) {
247
248
    extern void sdio_init(void);
    sdio_init();
249
    return mp_const_none;
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
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) {
    }
}

276
static mp_obj_t pyb_stop(void) {
277
278
279
280
281
282
283
284
285
286
287
288
    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);

289
    return mp_const_none;
290
291
}

292
static mp_obj_t pyb_standby(void) {
293
    PWR_EnterSTANDBYMode();
294
    return mp_const_none;
295
296
}

Damien's avatar
Damien committed
297
298
299
300
301
302
303
304
305
306
307
308
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};

309
void stdout_tx_str(const char *str) {
310
311
312
    if (pyb_usart_global_debug != PYB_USART_NONE) {
        usart_tx_str(pyb_usart_global_debug, str);
    }
313
314
315
    usb_vcp_send_str(str);
}

316
int readline(vstr_t *line, const char *prompt) {
317
    stdout_tx_str(prompt);
318
    int len = vstr_len(line);
Damien's avatar
Damien committed
319
320
    int escape = 0;
    int hist_num = 0;
321
    for (;;) {
322
323
324
325
326
        char c;
        for (;;) {
            if (usb_vcp_rx_any() != 0) {
                c = usb_vcp_rx_get();
                break;
327
328
            } else if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) {
                c = usart_rx_char(pyb_usart_global_debug);
329
                break;
330
            }
Damien's avatar
Damien committed
331
            sys_tick_delay_ms(1);
332
333
334
            if (storage_needs_flush()) {
                storage_flush();
            }
335
        }
Damien's avatar
Damien committed
336
337
338
339
        if (escape == 0) {
            if (c == 4 && vstr_len(line) == len) {
                return 0;
            } else if (c == '\r') {
340
                stdout_tx_str("\r\n");
Damien's avatar
Damien committed
341
342
343
344
345
346
347
348
349
350
                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);
351
                    stdout_tx_str("\b \b");
Damien's avatar
Damien committed
352
353
354
                }
            } else if (32 <= c && c <= 126) {
                vstr_add_char(line, c);
355
                stdout_tx_str(line->buf + line->len - 1);
356
            }
Damien's avatar
Damien committed
357
358
359
360
361
362
363
364
365
366
367
368
369
        } 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--) {
370
                        stdout_tx_str("\b \b");
Damien's avatar
Damien committed
371
372
373
374
375
                    }
                    // set line to history
                    line->len = len;
                    vstr_add_str(line, readline_hist[hist_num]);
                    // draw line
376
                    stdout_tx_str(readline_hist[hist_num]);
Damien's avatar
Damien committed
377
378
379
380
381
382
                    // increase hist num
                    hist_num += 1;
                }
            }
        } else {
            escape = 0;
383
        }
Damien's avatar
Damien committed
384
        sys_tick_delay_ms(10);
385
    }
386
387
}

388
void do_repl(void) {
389
    stdout_tx_str("Micro Python build <git hash> on 2/1/2014; PYBv3 with STM32F405RG\r\n");
390
    stdout_tx_str("Type \"help()\" for more information.\r\n");
391
392
393

    vstr_t line;
    vstr_init(&line);
394
395

    for (;;) {
396
397
398
        vstr_reset(&line);
        int ret = readline(&line, ">>> ");
        if (ret == 0) {
399
            // EOF
400
401
402
403
404
            break;
        }

        if (vstr_len(&line) == 0) {
            continue;
405
        }
406

407
        if (mp_repl_is_compound_stmt(vstr_str(&line))) {
408
            for (;;) {
409
410
411
412
413
                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
414
415
416
417
418
                    break;
                }
            }
        }

419
        mp_lexer_t *lex = mp_lexer_new_from_str_len("<stdin>", vstr_str(&line), vstr_len(&line), 0);
420
421
        mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT);
        mp_lexer_free(lex);
422

423
        if (pn != MP_PARSE_NODE_NULL) {
424
425
426
427
428
429
430
431
432
433
434
            mp_obj_t module_fun = mp_compile(pn, true);
            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);
435
                    }
436
437
438
439
                } else {
                    // uncaught exception
                    mp_obj_print((mp_obj_t)nlr.ret_val);
                    printf("\n");
440
441
442
443
                }
            }
        }
    }
444

445
    stdout_tx_str("\r\n");
446
447
448
}

bool do_file(const char *filename) {
449
450
    mp_lexer_file_buf_t fb;
    mp_lexer_t *lex = mp_lexer_new_from_file(filename, &fb);
451
452
453
454
455
456

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

457
458
    mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT);
    mp_lexer_free(lex);
459

460
    if (pn == MP_PARSE_NODE_NULL) {
461
462
463
        return false;
    }

464
    mp_obj_t module_fun = mp_compile(pn, false);
465
    if (module_fun == mp_const_none) {
466
467
468
469
470
471
472
473
474
475
        return false;
    }

    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
        rt_call_function_0(module_fun);
        nlr_pop();
        return true;
    } else {
        // uncaught exception
476
        mp_obj_print((mp_obj_t)nlr.ret_val);
477
478
479
        printf("\n");
        return false;
    }
480
481
}

482
483
484
485
486
487
#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);

488
void gc_collect(void) {
489
    uint32_t start = sys_tick_counter;
Damien's avatar
Damien committed
490
    gc_collect_start();
491
492
493
494
    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
495
    gc_collect_end();
496
    uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
497
498
499
500
501
502
503
504
505
506

    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);
    }
507
508
}

509
mp_obj_t pyb_gc(void) {
510
    gc_collect();
511
    return mp_const_none;
512
513
}

514
515
mp_obj_t pyb_gpio(int n_args, mp_obj_t *args) {
    //assert(1 <= n_args && n_args <= 2);
Damien's avatar
Damien committed
516

517
518
519
520
521
522
523
    const char *pin_name = qstr_str(mp_obj_get_qstr(args[0]));
    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;
524
    }
525
526
527
528
    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
529
        }
530
531
532
533
        pin_num = 10 * pin_num + *s - '0';
    }
    if (!(0 <= pin_num && pin_num <= 15)) {
        goto pin_error;
Damien's avatar
Damien committed
534
    }
535

536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
    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;
    }
554

555
pin_error:
556
    nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_ValueError, "pin %s does not exist", pin_name));
Damien's avatar
Damien committed
557
558
}

559
560
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio);

561
562
mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
    mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
563
    uint8_t data[4];
564
565
566
567
    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]);
568
    usb_hid_send_report(data);
569
    return mp_const_none;
570
571
}

572
static void rtc_init(void) {
573
574
575
    uint32_t rtc_clksrc;
    uint32_t timeout =10000;

576
577
578
579
580
581
582
583
584
585
    /* 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 */
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
    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;
603
604
605
    }

    /* Select the RTC Clock Source */
606
607
608
    RCC_RTCCLKConfig(rtc_clksrc);

    /* Note: LSI is around (32KHz), these dividers should work either way */
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
    /* 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);
}

646
mp_obj_t pyb_rtc_read(void) {
647
648
649
    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);
650
    return mp_const_none;
651
652
}

653
654
655
656
657
658
659
typedef struct _pyb_file_obj_t {
    mp_obj_base_t base;
    FIL fp;
} pyb_file_obj_t;

void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
    printf("<file %p>", self_in);
Damien's avatar
Damien committed
660
661
}

662
663
664
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);
Damien's avatar
Damien committed
665
666
    char *buf = m_new(char, n + 1);
    UINT n_out;
667
    f_read(&self->fp, buf, n, &n_out);
Damien's avatar
Damien committed
668
    buf[n_out] = 0;
669
    return mp_obj_new_str(qstr_from_str_take(buf, n + 1));
Damien's avatar
Damien committed
670
671
}

672
673
674
mp_obj_t file_obj_write(mp_obj_t self_in, mp_obj_t arg) {
    pyb_file_obj_t *self = self_in;
    const char *s = qstr_str(mp_obj_get_qstr(arg));
Damien's avatar
Damien committed
675
    UINT n_out;
676
    FRESULT res = f_write(&self->fp, s, strlen(s), &n_out);
Damien's avatar
Damien committed
677
678
679
680
681
    if (res != FR_OK) {
        printf("File error: could not write to file; error code %d\n", res);
    } else if (n_out != strlen(s)) {
        printf("File error: could not write all data to file; wrote %d / %d bytes\n", n_out, strlen(s));
    }
682
    return mp_const_none;
Damien's avatar
Damien committed
683
684
}

685
686
687
688
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
689
690
}

691
692
693
694
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
695
// TODO gc hook to close the file if not already closed
696

697
698
699
700
701
702
703
static const mp_method_t file_methods[] = {
    { "read", &file_obj_read_obj },
    { "write", &file_obj_write_obj },
    { "close", &file_obj_close_obj },
    {NULL, NULL},
};

704
705
static const mp_obj_type_t file_obj_type = {
    { &mp_const_type },
Damien's avatar
Damien committed
706
    "File",
707
708
    .print = file_obj_print,
    .methods = file_methods,
Damien's avatar
Damien committed
709
710
};

711
712
713
714
715
mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) {
    const char *filename = qstr_str(mp_obj_get_qstr(o_filename));
    const char *mode = qstr_str(mp_obj_get_qstr(o_mode));
    pyb_file_obj_t *self = m_new_obj(pyb_file_obj_t);
    self->base.type = &file_obj_type;
Damien's avatar
Damien committed
716
717
    if (mode[0] == 'r') {
        // open for reading
718
        FRESULT res = f_open(&self->fp, filename, FA_READ);
Damien's avatar
Damien committed
719
720
        if (res != FR_OK) {
            printf("FileNotFoundError: [Errno 2] No such file or directory: '%s'\n", filename);
721
            return mp_const_none;
Damien's avatar
Damien committed
722
723
724
        }
    } else if (mode[0] == 'w') {
        // open for writing, truncate the file first
725
        FRESULT res = f_open(&self->fp, filename, FA_WRITE | FA_CREATE_ALWAYS);
Damien's avatar
Damien committed
726
727
        if (res != FR_OK) {
            printf("?FileError: could not create file: '%s'\n", filename);
728
            return mp_const_none;
Damien's avatar
Damien committed
729
730
731
        }
    } else {
        printf("ValueError: invalid mode: '%s'\n", mode);
732
        return mp_const_none;
Damien's avatar
Damien committed
733
    }
734
    return self;
Damien's avatar
Damien committed
735
736
}

737
738
mp_obj_t pyb_rng_get(void) {
    return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
739
740
}

741
int main(void) {
742
    // TODO disable JTAG
Damien's avatar
Damien committed
743

744
745
746
    // update the SystemCoreClock variable
    SystemCoreClockUpdate();

747
748
749
750
751
752
    // 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
    RCC->AHB1ENR |= RCC_AHB1ENR_CCMDATARAMEN | RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;

753
    // configure SDIO pins to be high to start with (apparently makes it more robust)
754
755
756
757
758
759
760
761
762
763
764
765
766
767
    {
      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);
    }

768
769
    // basic sub-system init
    sys_tick_init();
Damien's avatar
Damien committed
770
    led_init();
771
    rtc_init();
772
773
774
775
776

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

    // more sub-system init
777
    switch_init();
778
    storage_init();
779

780
781
782
    // uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP
    //pyb_usart_global_debug = PYB_USART_6;
    //usart_init(pyb_usart_global_debug, 115200);
Damien's avatar
Damien committed
783

784
785
    int first_soft_reset = true;

786
787
soft_reset:

Damien's avatar
Damien committed
788
    // GC init
789
    gc_init(&_heap_start, (void*)HEAP_END);
Damien's avatar
Damien committed
790

791
    // Micro Python init
792
793
    qstr_init();
    rt_init();
794

795
    // LCD init
796
    //lcd_init(); disabled while servos on PA0 PA1
797

798
799
800
    // servo
    servo_init();

801
    // audio
802
    //audio_init();
803

804
805
806
    // timer
    timer_init();

807
    // RNG
808
    if (1) {
809
810
811
812
        RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
        RNG_Cmd(ENABLE);
    }

813
    // add some functions to the python namespace
814
    {
815
        rt_store_name(qstr_from_str_static("help"), rt_make_function_n(0, pyb_help));
816

817
        mp_obj_t m = mp_obj_new_module(qstr_from_str_static("pyb"));
818
819
820
821
822
823
824
825
826
827
        rt_store_attr(m, qstr_from_str_static("info"), rt_make_function_n(0, pyb_info));
        rt_store_attr(m, qstr_from_str_static("sd_test"), rt_make_function_n(0, pyb_sd_test));
        rt_store_attr(m, qstr_from_str_static("stop"), rt_make_function_n(0, pyb_stop));
        rt_store_attr(m, qstr_from_str_static("standby"), rt_make_function_n(0, pyb_standby));
        rt_store_attr(m, qstr_from_str_static("source_dir"), rt_make_function_n(1, pyb_source_dir));
        rt_store_attr(m, qstr_from_str_static("main"), rt_make_function_n(1, pyb_main));
        rt_store_attr(m, qstr_from_str_static("sync"), rt_make_function_n(0, pyb_sync));
        rt_store_attr(m, qstr_from_str_static("gc"), rt_make_function_n(0, pyb_gc));
        rt_store_attr(m, qstr_from_str_static("delay"), rt_make_function_n(1, pyb_delay));
        rt_store_attr(m, qstr_from_str_static("led"), rt_make_function_n(1, pyb_led));
828
        rt_store_attr(m, qstr_from_str_static("switch"), (mp_obj_t)&pyb_switch_obj);
829
830
        rt_store_attr(m, qstr_from_str_static("servo"), rt_make_function_n(2, pyb_servo_set));
        rt_store_attr(m, qstr_from_str_static("pwm"), rt_make_function_n(2, pyb_pwm_set));
831
832
833
        rt_store_attr(m, qstr_from_str_static("accel"), (mp_obj_t)&pyb_mma_read_obj);
        rt_store_attr(m, qstr_from_str_static("mma_read"), (mp_obj_t)&pyb_mma_read_all_obj);
        rt_store_attr(m, qstr_from_str_static("mma_mode"), (mp_obj_t)&pyb_mma_write_mode_obj);
834
835
836
837
838
839
        rt_store_attr(m, qstr_from_str_static("hid"), rt_make_function_n(1, pyb_hid_send_report));
        rt_store_attr(m, qstr_from_str_static("time"), rt_make_function_n(0, pyb_rtc_read));
        rt_store_attr(m, qstr_from_str_static("rand"), rt_make_function_n(0, pyb_rng_get));
        rt_store_attr(m, qstr_from_str_static("Led"), rt_make_function_n(1, pyb_Led));
        rt_store_attr(m, qstr_from_str_static("Servo"), rt_make_function_n(1, pyb_Servo));
        rt_store_attr(m, qstr_from_str_static("I2C"), rt_make_function_n(2, pyb_I2C));
840
        rt_store_attr(m, qstr_from_str_static("gpio"), (mp_obj_t)&pyb_gpio_obj);
841
        rt_store_attr(m, qstr_from_str_static("Usart"), rt_make_function_n(2, pyb_Usart));
842
        rt_store_name(qstr_from_str_static("pyb"), m);
Damien's avatar
Damien committed
843

844
        rt_store_name(qstr_from_str_static("open"), rt_make_function_n(2, pyb_io_open));
845
    }
846

847
848
    // print a message to the LCD
    lcd_print_str(" micro py board\n");
Damien's avatar
Damien committed
849

850
851
    // check if user switch held (initiates reset of filesystem)
    bool reset_filesystem = false;
852
    if (switch_get()) {
853
854
        reset_filesystem = true;
        for (int i = 0; i < 50; i++) {
855
            if (!switch_get()) {
856
857
858
859
860
861
862
                reset_filesystem = false;
                break;
            }
            sys_tick_delay_ms(10);
        }
    }

863
864
865
866
    // local filesystem init
    {
        // try to mount the flash
        FRESULT res = f_mount(&fatfs0, "0:", 1);
867
        if (!reset_filesystem && res == FR_OK) {
868
            // mount sucessful
869
        } else if (reset_filesystem || res == FR_NO_FILESYSTEM) {
870
            // no filesystem, so create a fresh one
871
            // TODO doesn't seem to work correctly when reset_filesystem is true...
872
873
874
875
876
877
878
879
880
881
882
883

            // 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");
            }

884
885
886
887
888
889
890
891
892
893
894
895
            // 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);

896
897
            // keep LED on for at least 200ms
            sys_tick_wait_at_least(stc, 200);
898
899
900
901
            led_state(PYB_LED_R2, 0);
        } else {
            __fatal_error("could not access LFS");
        }
Damien's avatar
Damien committed
902
903
    }

904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
    // 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;
926
            f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
927
928
929
            // TODO check we could write n bytes
            f_close(&fp);

930
931
            // keep LED on for at least 200ms
            sys_tick_wait_at_least(stc, 200);
932
933
934
935
            led_state(PYB_LED_R2, 0);
        }
    }

936
937
938
939
940
    // run /boot.py
    if (!do_file("0:/boot.py")) {
        flash_error(4);
    }

941
942
943
    // USB
    usb_init();

944
945
946
    // USB host; not working!
    //pyb_usbh_init();

Damien's avatar
Damien committed
947
    // MMA
948
    if (first_soft_reset) {
Damien's avatar
Damien committed
949
950
951
952
        // init and reset address to zero
        mma_init();
    }

953
954
    // turn boot-up LED off
    led_state(PYB_LED_G1, 0);
955

956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
    // run main script
    {
        vstr_t *vstr = vstr_new();
        vstr_add_str(vstr, "0:/");
        if (pyb_config_source_dir == 0) {
            vstr_add_str(vstr, "src");
        } else {
            vstr_add_str(vstr, qstr_str(pyb_config_source_dir));
        }
        vstr_add_char(vstr, '/');
        if (pyb_config_main == 0) {
            vstr_add_str(vstr, "main.py");
        } else {
            vstr_add_str(vstr, qstr_str(pyb_config_main));
        }
        if (!do_file(vstr_str(vstr))) {
            flash_error(3);
973
        }
974
        vstr_free(vstr);
975
976
    }

Damien's avatar
Damien committed
977
    //printf("init;al=%u\n", m_get_total_bytes_allocated()); // 1600, due to qstr_init
978
    //sys_tick_delay_ms(1000);
Damien's avatar
Damien committed
979
980

    // Python!
981
    if (0) {
Damien's avatar
Damien committed
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
        //const char *pysrc = "def f():\n  x=x+1\nprint(42)\n";
        const char *pysrc =
            // impl01.py
            /*
            "x = 0\n"
            "while x < 400:\n"
            "    y = 0\n"
            "    while y < 400:\n"
            "        z = 0\n"
            "        while z < 400:\n"
            "            z = z + 1\n"
            "        y = y + 1\n"
            "    x = x + 1\n";
            */
            // impl02.py
997
            /*
Damien's avatar
Damien committed
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
            "#@micropython.native\n"
            "def f():\n"
            "    x = 0\n"
            "    while x < 400:\n"
            "        y = 0\n"
            "        while y < 400:\n"
            "            z = 0\n"
            "            while z < 400:\n"
            "                z = z + 1\n"
            "            y = y + 1\n"
            "        x = x + 1\n"
            "f()\n";
1010
            */
1011
            /*
Damien's avatar
Damien committed
1012
1013
1014
1015
1016
1017
1018
            "print('in python!')\n"
            "x = 0\n"
            "while x < 4:\n"
            "    pyb_led(True)\n"
            "    pyb_delay(201)\n"
            "    pyb_led(False)\n"
            "    pyb_delay(201)\n"
1019
            "    x += 1\n"
Damien's avatar
Damien committed
1020
1021
1022
            "print('press me!')\n"
            "while True:\n"
            "    pyb_led(pyb_sw())\n";
1023
            */
Damien's avatar
Damien committed
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
            /*
            // impl16.py
            "@micropython.asm_thumb\n"
            "def delay(r0):\n"
            "    b(loop_entry)\n"
            "    label(loop1)\n"
            "    movw(r1, 55999)\n"
            "    label(loop2)\n"
            "    subs(r1, r1, 1)\n"
            "    cmp(r1, 0)\n"
            "    bgt(loop2)\n"
            "    subs(r0, r0, 1)\n"
            "    label(loop_entry)\n"
            "    cmp(r0, 0)\n"
            "    bgt(loop1)\n"
            "print('in python!')\n"
            "@micropython.native\n"
            "def flash(n):\n"
            "    x = 0\n"
            "    while x < n:\n"
            "        pyb_led(True)\n"
            "        delay(249)\n"
            "        pyb_led(False)\n"
            "        delay(249)\n"
            "        x = x + 1\n"
            "flash(20)\n";
            */
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
            // impl18.py
            /*
            "# basic exceptions\n"
            "x = 1\n"
            "try:\n"
            "    x.a()\n"
            "except:\n"
            "    print(x)\n";
            */
            // impl19.py
            "# for loop\n"
            "def f():\n"
            "    for x in range(400):\n"
            "        for y in range(400):\n"
            "            for z in range(400):\n"
            "                pass\n"
            "f()\n";
Damien's avatar
Damien committed
1068

1069
        mp_lexer_t *lex = mp_lexer_new_from_str_len("<stdin>", pysrc, strlen(pysrc), 0);
Damien's avatar
Damien committed
1070

1071
1072
1073
        // nalloc=1740;6340;6836 -> 140;4600;496 bytes for lexer, parser, compiler
        printf("lex; al=%u\n", m_get_total_bytes_allocated());
        sys_tick_delay_ms(1000);
1074
1075
1076
        mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT);
        mp_lexer_free(lex);
        if (pn != MP_PARSE_NODE_NULL) {
Damien's avatar
Damien committed
1077
            printf("pars;al=%u\n", m_get_total_bytes_allocated());
1078
            sys_tick_delay_ms(1000);
Damien's avatar
Damien committed
1079
            //parse_node_show(pn, 0);
1080
            mp_obj_t module_fun = mp_compile(pn, false);
Damien's avatar
Damien committed
1081
            printf("comp;al=%u\n", m_get_total_bytes_allocated());
1082
            sys_tick_delay_ms(1000);
Damien's avatar
Damien committed
1083

1084
            if (module_fun == mp_const_none) {
1085
1086
                printf("compile error\n");
            } else {
Damien's avatar
Damien committed
1087
1088
                // execute it!

1089
                // flash once
1090
                led_state(PYB_LED_G1, 1);
1091
                sys_tick_delay_ms(100);
1092
                led_state(PYB_LED_G1, 0);
1093
1094
1095

                nlr_buf_t nlr;
                if (nlr_push(&nlr) == 0) {
1096
                    mp_obj_t ret = rt_call_function_0(module_fun);
1097
                    printf("done! got: ");
1098
                    mp_obj_print(ret);
1099
1100
1101
1102
1103
                    printf("\n");
                    nlr_pop();
                } else {
                    // uncaught exception
                    printf("exception: ");
1104
                    mp_obj_print((mp_obj_t)nlr.ret_val);
1105
1106
1107
1108
                    printf("\n");
                }

                // flash once
1109
                led_state(PYB_LED_G1, 1);
1110
                sys_tick_delay_ms(100);
1111
                led_state(PYB_LED_G1, 0);
Damien's avatar
Damien committed
1112

1113
                sys_tick_delay_ms(1000);
Damien's avatar
Damien committed
1114
                printf("nalloc=%u\n", m_get_total_bytes_allocated());
1115
                sys_tick_delay_ms(1000);
Damien's avatar
Damien committed
1116
1117
1118
1119
            }
        }
    }

1120
1121
1122
1123
1124
1125
1126
1127
    // HID example
    if (0) {
        uint8_t data[4];
        data[0] = 0;
        data[1] = 1;
        data[2] = -2;
        data[3] = 0;
        for (;;) {
1128
            if (switch_get()) {
1129
1130
1131
1132
                data[0] = 0x01; // 0x04 is middle, 0x02 is right
            } else {
                data[0] = 0x00;
            }
1133
            mma_start(0x4c /* MMA_ADDR */, 1);
1134
            mma_send_byte(0);
1135
            mma_restart(0x4c /* MMA_ADDR */, 0);
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
            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);
        }
    }

1149
    // wifi
1150
1151
    //pyb_wlan_init();
    //pyb_wlan_start();
1152

1153
1154
    do_repl();

Damien's avatar
Damien committed
1155
1156
    // benchmark C version of impl02.py
    if (0) {
1157
        led_state(PYB_LED_G1, 1);
1158
        sys_tick_delay_ms(100);
1159
        led_state(PYB_LED_G1, 0);