Initial commit of code
[barbilliards.git] / src / timer.c
1 // vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
2 /*
3  * This file is part of the libopencm3 project.
4  *
5  * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
6  *
7  * This library is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <libopencm3/stm32/rcc.h>
24 #include <libopencm3/stm32/gpio.h>
25 #include <libopencm3/cm3/nvic.h>
26 #include <libopencm3/cm3/systick.h>
27 #include <libopencm3/usb/usbd.h>
28 #include <libopencm3/usb/cdc.h>
29
30 #include "usb_cdcacm.h"
31
32 uint32_t n_millis_total = 0;
33 uint32_t n_millis_cur = 0;
34 uint8_t n_millis_loops = 0;
35 usbd_device *usbd_dev;
36 static uint32_t game_time = 14 * 60 * 1000; // 15 minutes of 1ms ticks
37
38 void sys_tick_handler(void) {
39     ++n_millis_cur;
40     ++n_millis_total;
41
42     if (n_millis_total >= game_time) {
43         gpio_clear(GPIOC, GPIO13); // turn on LED
44         return;
45     }
46
47     /* calculate remaining seconds to print out on the serial port, only do this every
48        1000 millis or so */
49     if (n_millis_loops >= 4) {
50         char seconds_remaining[5];
51         sprintf(seconds_remaining, "%d", (int)((game_time - n_millis_total) / 1000));
52         for (int i = 0; i < 4; i++) {
53             cdcacm_putchar(seconds_remaining[i]);
54         }
55         cdcacm_putchar('\r');
56         cdcacm_putchar('\n');
57     }
58
59     if (n_millis_cur >= 250) {
60         gpio_toggle(GPIOC, GPIO13);
61         ++n_millis_loops;
62         n_millis_cur = 0;
63         return;
64     }
65
66     return;
67 }
68
69 static void clock_setup(void) {
70     /* Run CPU at 72MHz */
71     rcc_clock_setup_in_hse_8mhz_out_72mhz();
72     rcc_periph_clock_enable(RCC_GPIOA);
73     rcc_periph_clock_enable(RCC_GPIOC);
74
75     /* 72MHz / 8 => 9000000 counts per second */
76     systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
77
78     /* 9000000 / 9000 = 1000 overflows per second - every 1ms one interrupt */
79     /* SysTick interrupt every N clock pulses: set reload to N-1 */
80     systick_set_reload(8999); // 1 ms
81     systick_interrupt_enable();
82     systick_counter_enable();
83 }
84
85 static void gpio_setup(void) {
86     // Built-in LED on blue pill board, PC13
87     gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
88         GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
89     gpio_set(GPIOC, GPIO13);
90
91     // Pull up the USB D+ line for reset
92     gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
93       GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12);
94     gpio_clear(GPIOA, GPIO12);
95 }
96
97 int main(void)
98 {
99     clock_setup();
100     gpio_setup();
101     cdcacm_setup();
102
103     gpio_set(GPIOC, GPIO13);
104
105     while (1) {
106         __asm__("nop");
107     }
108
109     return 0;
110 }
111