Blame view

RIOT/cpu/stm32_common/periph/rtt_lptim.c 3.71 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  /*
   * Copyright (C) 2017 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @ingroup     cpu_stm32_common
   * @ingroup     drivers_periph_rtt
   * @{
   *
   * @file
   * @brief       RTT implementation using LPTIM1
   *
   * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
   *
   * @}
   */
  
  #include "cpu.h"
  #include "irq.h"
  #include "periph/rtt.h"
  
  /* this driver is only valid for STM CPUs that provide LPTIMERs */
  #if (defined(LPTIM1) && RTT_NUMOF)
  
  /* figure out the used pre-scaler */
  #if (RTT_FREQUENCY == 32768)
  #define PRE                 (0)
  #elif (RTT_FREQUENCY == 16384)
  #define PRE                 (LPTIM_CFGR_PRESC_0)
  #elif (RTT_FREQUENCY == 8192)
  #define PRE                 (LPTIM_CFGR_PRESC_1)
  #elif (RTT_FREQUENCY == 4096)
  #define PRE                 (LPTIM_CFGR_PRESC_1 | LPTIM_CFGR_PRESC_0)
  #elif (RTT_FREQUENCY == 2048)
  #define PRE                 (LPTIM_CFGR_PRESC_2)
  #elif (RTT_FREQUENCY == 1024)
  #define PRE                 (LPTIM_CFGR_PRESC_2 | LPTIM_CFGR_PRESC_0)
  #elif (RTT_FREQUENCY == 512)
  #define PRE                 (LPTIM_CFGR_PRESC_2 | LPTIM_CFGR_PRESC_1)
  #elif (RTT_FREQUENCY == 256)
  #define PRE                 (LPTIM_CFGR_PRESC)
  #else
  #error "RTT config: RTT_FREQUENCY not configured or invalid for your board"
  #endif
  
  /* allocate memory for overflow and alarm callbacks + args */
  static rtt_cb_t ovf_cb = NULL;
  static void *ovf_arg;
  static rtt_cb_t to_cb = NULL;
  static void *to_arg;
  
  void rtt_init(void)
  {
      /* power on the selected LPTIMER */
      rtt_poweron();
  
      /* stop the timer and reset configuration */
      LPTIM1->CR = 0;
  
      /* select low speed clock (LSI or LSE) */
      RCC->CCIPR &= ~(RCC_CCIPR_LPTIM1SEL);
  #if CLOCK_LSE
      RCC->CCIPR |= (RCC_CCIPR_LPTIM1SEL_1 | RCC_CCIPR_LPTIM1SEL_0);
  #else
      RCC->CCIPR |= (RCC_CCIPR_LPTIM1SEL_0);
  #endif
  
      /* set configuration: prescale factor and external clock (LSI or LSE) */
      LPTIM1->CFGR = PRE;
      /* enable overflow and compare interrupts */
      LPTIM1->IER = (LPTIM_IER_ARRMIE | LPTIM_IER_CMPMIE);
      NVIC_EnableIRQ(LPTIM1_IRQn);
      /* enable timer */
      LPTIM1->CR = LPTIM_CR_ENABLE;
      /* set auto-reload value (timer needs to be enabled for this) */
      LPTIM1->ARR = RTT_MAX_VALUE;
      /* start the timer */
      LPTIM1->CR |= LPTIM_CR_CNTSTRT;
  }
  
  uint32_t rtt_get_counter(void)
  {
      return (uint32_t)LPTIM1->CNT;
  }
  
  void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
  {
      assert(cb);
  
      unsigned is = irq_disable();
      ovf_cb  = cb;
      ovf_arg = arg;
      irq_restore(is);
  }
  
  void rtt_clear_overflow_cb(void)
  {
      ovf_cb = NULL;
  }
  
  void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
  {
      assert(cb && !(alarm & ~RTT_MAX_VALUE));
  
      unsigned is = irq_disable();
      to_cb  = cb;
      to_arg = arg;
      LPTIM1->CMP = (uint16_t)alarm;
      irq_restore(is);
  }
  
  void rtt_clear_alarm(void)
  {
      to_cb = NULL;
  }
  
  void rtt_poweron(void)
  {
  #ifdef RCC_APB1ENR1_LPTIM1EN
      periph_clk_en(APB1, RCC_APB1ENR1_LPTIM1EN);
  #else
      periph_clk_en(APB1, RCC_APB1ENR_LPTIM1EN);
  #endif
  }
  
  void rtt_poweroff(void)
  {
  #ifdef RCC_APB1ENR1_LPTIM1EN
      periph_clk_dis(APB1, RCC_APB1ENR1_LPTIM1EN);
  #else
      periph_clk_dis(APB1, RCC_APB1ENR_LPTIM1EN);
  #endif
  }
  
  void isr_lptim1(void)
  {
      if (LPTIM1->ISR & LPTIM_ISR_CMPM) {
          if (to_cb) {
              /* 'consume' the callback (as it might be set again in the cb) */
              rtt_cb_t tmp = to_cb;
              to_cb = NULL;
              tmp(to_arg);
          }
      }
      if (LPTIM1->ISR & LPTIM_ISR_ARRM) {
          if (ovf_cb) {
              ovf_cb(ovf_arg);
          }
      }
      LPTIM1->ICR = (LPTIM_ICR_ARRMCF | LPTIM_ICR_CMPMCF);
  
      cortexm_isr_end();
  }
  
  #endif /* LPTIM1 */