main.c 29.9 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
65
66
67
void __fatal_error(const char *msg) {
    lcd_print_strn("\nFATAL ERROR:\n", 14);
    lcd_print_strn(msg, strlen(msg));
    for (;;) {
68
        flash_error(1);
Damien's avatar
Damien committed
69
70
71
    }
}

72
73
static mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
static mp_obj_t pyb_config_main = MP_OBJ_NULL;
74

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

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

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

95
96
97
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
98
99
}

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

107
static const char fresh_boot_py[] =
108
109
110
111
112
113
114
115
116
117
118
"# 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"
;

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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"
137
138
"    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"
139
140
141
;

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

147
// get lots of info about the board
148
static mp_obj_t pyb_info(void) {
149
150
151
152
153
154
    // 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]);
    }

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
    // 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);
    }

182
183
184
185
186
187
188
189
190
191
    // 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);
    }

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

200
    return mp_const_none;
201
202
}

203
// SD card test
204
static mp_obj_t pyb_sd_test(void) {
205
206
    extern void sdio_init(void);
    sdio_init();
207
    return mp_const_none;
208
209
}

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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) {
    }
}

234
static mp_obj_t pyb_stop(void) {
235
236
237
238
239
240
241
242
243
244
245
246
    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);

247
    return mp_const_none;
248
249
}

250
static mp_obj_t pyb_standby(void) {
251
    PWR_EnterSTANDBYMode();
252
    return mp_const_none;
253
254
}

Damien's avatar
Damien committed
255
256
257
258
259
260
261
262
263
264
265
266
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};

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

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

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

    vstr_t line;
351
    vstr_init(&line, 32);
352
353

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

        if (vstr_len(&line) == 0) {
            continue;
363
        }
364

365
        if (mp_repl_is_compound_stmt(vstr_str(&line))) {
366
            for (;;) {
367
368
369
370
371
                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
372
373
374
375
376
                    break;
                }
            }
        }

377
        mp_lexer_t *lex = mp_lexer_new_from_str_len("<stdin>", vstr_str(&line), vstr_len(&line), 0);
378
379
380
        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);
381
        qstr source_name = mp_lexer_source_name(lex);
382
383
384
385
386
387
388
389
390

        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);
391
            mp_obj_t module_fun = mp_compile(pn, source_name, true);
392
393
394
395
396
397
398
399
400
401
            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);
402
                    }
403
404
                } else {
                    // uncaught exception
405
                    mp_obj_print_exception((mp_obj_t)nlr.ret_val);
406
407
408
409
                }
            }
        }
    }
410

411
    stdout_tx_str("\r\n");
412
413
414
}

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

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

422
423
424
    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);
425
    qstr source_name = mp_lexer_source_name(lex);
426

427
    if (pn == MP_PARSE_NODE_NULL) {
428
429
430
431
        // 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);
432
433
434
        return false;
    }

435
436
    mp_lexer_free(lex);

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

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

454
455
456
457
458
459
#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);

460
void gc_collect(void) {
461
    uint32_t start = sys_tick_counter;
Damien's avatar
Damien committed
462
    gc_collect_start();
463
464
465
466
    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
467
    gc_collect_end();
468
    uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
469
470
471
472
473
474
475
476
477
478

    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);
    }
479
480
}

481
mp_obj_t pyb_gc(void) {
482
    gc_collect();
483
    return mp_const_none;
484
485
}

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

489
    const char *pin_name = mp_obj_str_get_str(args[0]);
490
491
492
493
494
495
    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;
496
    }
497
498
499
500
    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
501
        }
502
503
504
505
        pin_num = 10 * pin_num + *s - '0';
    }
    if (!(0 <= pin_num && pin_num <= 15)) {
        goto pin_error;
Damien's avatar
Damien committed
506
    }
507

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
    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;
    }
526

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

531
532
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio);

533
534
mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
    mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
535
    uint8_t data[4];
536
537
538
539
    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]);
540
    usb_hid_send_report(data);
541
    return mp_const_none;
542
543
}

544
static void rtc_init(void) {
545
    uint32_t rtc_clksrc;
546
    uint32_t timeout = 1000000;
547

548
549
550
551
552
553
554
555
556
557
    /* 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 */
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
    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;
575
576
577
    }

    /* Select the RTC Clock Source */
578
579
580
    RCC_RTCCLKConfig(rtc_clksrc);

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

618
mp_obj_t pyb_rtc_read(void) {
619
620
621
    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);
622
    return mp_const_none;
623
624
}

625
626
627
628
629
typedef struct _pyb_file_obj_t {
    mp_obj_base_t base;
    FIL fp;
} pyb_file_obj_t;

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

634
635
636
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);
637
    byte *buf = m_new(byte, n);
Damien's avatar
Damien committed
638
    UINT n_out;
639
    f_read(&self->fp, buf, n, &n_out);
640
    return mp_obj_new_str(buf, n_out, false);
Damien's avatar
Damien committed
641
642
}

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

657
658
659
660
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
661
662
}

663
664
665
666
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
667
// TODO gc hook to close the file if not already closed
668

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

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

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

709
710
mp_obj_t pyb_rng_get(void) {
    return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
711
712
}

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

716
717
718
    // update the SystemCoreClock variable
    SystemCoreClockUpdate();

719
720
721
722
    // 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
723
724
725
726
727
    RCC->AHB1ENR |= RCC_AHB1ENR_CCMDATARAMEN | RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN
#if defined(STM32F4DISC)
        | RCC_AHB1ENR_GPIODEN
#endif
        ;
728

729
    // configure SDIO pins to be high to start with (apparently makes it more robust)
730
731
732
733
734
735
736
737
738
739
740
741
742
743
    {
      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);
    }

744
745
    // basic sub-system init
    sys_tick_init();
Damien's avatar
Damien committed
746
    led_init();
747
    rtc_init();
748
749
750
751
752

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

    // more sub-system init
753
    switch_init();
754
    storage_init();
755

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

760
761
    int first_soft_reset = true;

762
763
soft_reset:

Damien's avatar
Damien committed
764
    // GC init
765
    gc_init(&_heap_start, (void*)HEAP_END);
Damien's avatar
Damien committed
766

767
    // Micro Python init
768
769
    qstr_init();
    rt_init();
770

771
772
    // LCD init (create in with LCD())
    lcd_init();
773

774
775
776
    // servo
    servo_init();

777
    // audio
778
    //audio_init();
779

780
781
782
    // timer
    timer_init();

783
    // RNG
784
    if (1) {
785
786
787
788
        RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
        RNG_Cmd(ENABLE);
    }

789
    // add some functions to the python namespace
790
    {
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
        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));
        rt_store_attr(m, MP_QSTR_sd_test, rt_make_function_n(0, pyb_sd_test));
        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));
        rt_store_attr(m, MP_QSTR_switch, (mp_obj_t)&pyb_switch_obj);
        rt_store_attr(m, MP_QSTR_servo, rt_make_function_n(2, pyb_servo_set));
        rt_store_attr(m, MP_QSTR_pwm, rt_make_function_n(2, pyb_pwm_set));
mux's avatar
mux committed
806
#if MICROPY_HW_HAS_MMA7660
807
808
809
        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);
810
#endif
811
812
813
        rt_store_attr(m, MP_QSTR_hid, rt_make_function_n(1, pyb_hid_send_report));
        rt_store_attr(m, MP_QSTR_time, rt_make_function_n(0, pyb_rtc_read));
        rt_store_attr(m, MP_QSTR_rand, rt_make_function_n(0, pyb_rng_get));
814
        rt_store_attr(m, MP_QSTR_Led, (mp_obj_t)&pyb_Led_obj);
815
816
817
818
819
820
821
822
        rt_store_attr(m, MP_QSTR_Servo, rt_make_function_n(1, pyb_Servo));
        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));
823
    }
824

825
826
    // print a message to the LCD
    lcd_print_str(" micro py board\n");
Damien's avatar
Damien committed
827

828
829
    // check if user switch held (initiates reset of filesystem)
    bool reset_filesystem = false;
830
    if (switch_get()) {
831
832
        reset_filesystem = true;
        for (int i = 0; i < 50; i++) {
833
            if (!switch_get()) {
834
835
836
837
838
839
840
                reset_filesystem = false;
                break;
            }
            sys_tick_delay_ms(10);
        }
    }

841
842
843
844
    // local filesystem init
    {
        // try to mount the flash
        FRESULT res = f_mount(&fatfs0, "0:", 1);
845
        if (!reset_filesystem && res == FR_OK) {
846
            // mount sucessful
847
        } else if (reset_filesystem || res == FR_NO_FILESYSTEM) {
848
            // no filesystem, so create a fresh one
849
            // TODO doesn't seem to work correctly when reset_filesystem is true...
850
851
852
853
854
855
856
857
858
859
860
861

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

862
863
864
865
866
867
868
869
870
871
872
873
            // 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);

874
875
            // keep LED on for at least 200ms
            sys_tick_wait_at_least(stc, 200);
876
877
878
879
            led_state(PYB_LED_R2, 0);
        } else {
            __fatal_error("could not access LFS");
        }
Damien's avatar
Damien committed
880
881
    }

882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
    // 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;
904
            f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
905
906
907
            // TODO check we could write n bytes
            f_close(&fp);

908
909
            // keep LED on for at least 200ms
            sys_tick_wait_at_least(stc, 200);
910
911
912
913
            led_state(PYB_LED_R2, 0);
        }
    }

914
915
916
917
918
    // run /boot.py
    if (!do_file("0:/boot.py")) {
        flash_error(4);
    }

919
920
921
    // USB
    usb_init();

922
923
    // USB host; not working!
    //pyb_usbh_init();
924
925
    //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));
926

927
    if (first_soft_reset) {
mux's avatar
mux committed
928
#if MICROPY_HW_HAS_MMA7660
929
        // MMA: init and reset address to zero
Damien's avatar
Damien committed
930
        mma_init();
931
#endif
Damien's avatar
Damien committed
932
933
    }

934
935
    // turn boot-up LED off
    led_state(PYB_LED_G1, 0);
936

937
938
939
940
    // run main script
    {
        vstr_t *vstr = vstr_new();
        vstr_add_str(vstr, "0:/");
941
        if (pyb_config_source_dir == MP_OBJ_NULL) {
942
943
            vstr_add_str(vstr, "src");
        } else {
944
            vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_source_dir));
945
946
        }
        vstr_add_char(vstr, '/');
947
        if (pyb_config_main == MP_OBJ_NULL) {
948
949
            vstr_add_str(vstr, "main.py");
        } else {
950
            vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main));
951
952
953
        }
        if (!do_file(vstr_str(vstr))) {
            flash_error(3);
954
        }
955
        vstr_free(vstr);
956
957
    }

Damien's avatar
Damien committed
958

mux's avatar
mux committed
959
#if MICROPY_HW_HAS_MMA7660
960
961
962
963
964
965
966
967
    // HID example
    if (0) {
        uint8_t data[4];
        data[0] = 0;
        data[1] = 1;
        data[2] = -2;
        data[3] = 0;
        for (;;) {
968
            if (switch_get()) {
969
970
971
972
                data[0] = 0x01; // 0x04 is middle, 0x02 is right
            } else {
                data[0] = 0x00;
            }
973
            mma_start(0x4c /* MMA_ADDR */, 1);
974
            mma_send_byte(0);
975
            mma_restart(0x4c /* MMA_ADDR */, 0);
976
977
978
979
980
981
982
983
984
985
986
987
            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);
        }
    }
988
#endif
989

990
    // wifi
991
992
    //pyb_wlan_init();
    //pyb_wlan_start();
993

994
995
    do_repl();

996
997
998
999
    printf("PYB: sync filesystems\n");
    pyb_sync();

    printf("PYB: soft reboot\n");
1000
1001

    first_soft_reset = false;
1002
    goto soft_reset;
Damien's avatar
Damien committed
1003
}
1004

1005
1006
// these 2 functions seem to actually work... no idea why
// replacing with libgcc does not work (probably due to wrong calling conventions)
1007
1008
1009
1010
double __aeabi_f2d(float x) {
    // TODO
    return 0.0;
}
Damien's avatar
Damien committed
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020

float __aeabi_d2f(double x) {
    // TODO
    return 0.0;
}

double sqrt(double x) {
    // TODO
    return 0.0;
}
1021
1022
1023
1024
1025

machine_float_t machine_sqrt(machine_float_t x) {
    // TODO
    return x;
}