-
Notifications
You must be signed in to change notification settings - Fork 163
/
Copy pathbsp.c
325 lines (294 loc) · 13 KB
/
bsp.c
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
//============================================================================
// BSP for "real-time" Example
//
// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
// Q u a n t u m L e a P s
// ------------------------
// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
// This software is dual-licensed under the terms of the open-source GNU
// General Public License (GPL) or under the terms of one of the closed-
// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
// NOTE:
// The GPL does NOT permit the incorporation of this code into proprietary
// programs. Please contact Quantum Leaps for commercial licensing options,
// which expressly supersede the GPL and are designed explicitly for
// closed-source distribution.
//
// Quantum Leaps contact information:
// <www.state-machine.com/licensing>
// <info@state-machine.com>
//============================================================================
#include "qpc.h" // QP/C real-time event framework
#include "bsp.h" // Board Support Package
#include "app.h" // Application interface
#include "stm32c0xx.h" // CMSIS-compliant header file for the MCU used
// add other drivers if necessary...
Q_DEFINE_THIS_FILE // define the name of this file for assertions
// Local-scope defines -----------------------------------------------------
// test pins on GPIO PA (output)
#define TST1_PIN 7U
#define TST2_PIN 6U
#define TST3_PIN 4U
#define TST4_PIN 1U
#define TST5_PIN 0U
#define TST6_PIN 9U
#define TST7_PIN 5U // LED LD2-Green
// Button pins available on the board (just one user Button B1 on PC.13)
// button on GPIO PC (input)
#define B1_PIN 13U
//============================================================================
// Error handler and ISRs...
Q_NORETURN Q_onError(char const * const module, int_t const id) {
// NOTE: this implementation of the error handler is intended only
// for debugging and MUST be changed for deployment of the application
// (assuming that you ship your production code with assertions enabled).
Q_UNUSED_PAR(module);
Q_UNUSED_PAR(id);
QS_ASSERTION(module, id, 10000U); // report assertion to QS
#ifndef NDEBUG
// light up the user LED
GPIOA->BSRR = (1U << TST7_PIN); // turn LED on
// for debugging, hang on in an endless loop...
for (;;) {
}
#endif
NVIC_SystemReset();
}
//............................................................................
// assertion failure handler for the STM32 library, including the startup code
void assert_failed(char const * const module, int_t const id); // prototype
void assert_failed(char const * const module, int_t const id) {
Q_onError(module, id);
}
//............................................................................
#ifdef __UVISION_VERSION
// dummy initialization of the ctors (not used in C)
void _init(void);
void _init(void) {
}
#endif // __UVISION_VERSION
// ISRs used in the application ============================================
void SysTick_Handler(void); // prototype
void SysTick_Handler(void) {
BSP_d1on();
QTIMEEVT_TICK_X(0U, &l_SysTick_Handler); // time events at rate 0
// Perform the debouncing of buttons. The algorithm for debouncing
// adapted from the book "Embedded Systems Dictionary" by Jack Ganssle
// and Michael Barr, page 71.
static struct {
uint32_t depressed;
uint32_t previous;
} buttons = { 0U, 0U };
uint32_t current = ~GPIOC->IDR; // read Port C with state of Button B1
uint32_t tmp = buttons.depressed; // save the depressed buttons
buttons.depressed |= (buttons.previous & current); // set depressed
buttons.depressed &= (buttons.previous | current); // clear released
buttons.previous = current; // update the history
tmp ^= buttons.depressed; // changed debounced depressed
current = buttons.depressed;
if ((tmp & (1U << B1_PIN)) != 0U) { // debounced B1 state changed?
if ((current & (1U << B1_PIN)) != 0U) { // is B1 depressed?
// immutable sporadic-press event
static SporadicSpecEvt const sporadicA = {
QEVT_INITIALIZER(SPORADIC_A_SIG),
.toggles = 189U,
};
// immutable forward-press event
static SporadicSpecEvt const sporadicB = {
QEVT_INITIALIZER(SPORADIC_B_SIG),
.toggles = 89U,
};
QACTIVE_POST(AO_Sporadic2, &sporadicA.super, &l_SysTick_Handler);
QACTIVE_POST(AO_Sporadic2, &sporadicB.super, &l_SysTick_Handler);
}
else { // B1 is released
QACTIVE_POST(AO_Periodic4, BSP_getEvtPeriodic4(0U), &l_SysTick_Handler);
QACTIVE_POST(AO_Periodic1, BSP_getEvtPeriodic1(0U), &l_SysTick_Handler);
}
}
QV_ARM_ERRATUM_838869();
BSP_d1off();
}
// BSP functions =============================================================
void BSP_init(void) {
// Configure the MPU to prevent NULL-pointer dereferencing ...
MPU->RBAR = 0x0U // base address (NULL)
| MPU_RBAR_VALID_Msk // valid region
| (MPU_RBAR_REGION_Msk & 7U); // region #7
MPU->RASR = (7U << MPU_RASR_SIZE_Pos) // 2^(7+1) region
| (0x0U << MPU_RASR_AP_Pos) // no-access region
| MPU_RASR_ENABLE_Msk; // region enable
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk // enable background region
| MPU_CTRL_ENABLE_Msk; // enable the MPU
__ISB();
__DSB();
// enable GPIO port PA clock
RCC->IOPENR |= (1U << 0U);
// set all used GPIOA pins as push-pull output, no pull-up, pull-down
GPIOA->MODER &=
~((3U << 2U*TST1_PIN) | (3U << 2U*TST2_PIN) | (3U << 2U*TST3_PIN) |
(3U << 2U*TST4_PIN) | (3U << 2U*TST5_PIN) | (3U << 2U*TST6_PIN) |
(3U << 2U*TST7_PIN));
GPIOA->MODER |=
((1U << 2U*TST1_PIN) | (1U << 2U*TST2_PIN) | (1U << 2U*TST3_PIN) |
(1U << 2U*TST4_PIN) | (1U << 2U*TST5_PIN) | (1U << 2U*TST6_PIN) |
(1U << 2U*TST7_PIN));
GPIOA->OTYPER &=
~((1U << TST1_PIN) | (1U << TST2_PIN) | (1U << TST3_PIN) |
(1U << TST4_PIN) | (1U << TST5_PIN) | (1U << TST6_PIN) |
(1U << TST7_PIN));
GPIOA->PUPDR &=
~((3U << 2U*TST1_PIN) | (3U << 2U*TST2_PIN) | (3U << 2U*TST3_PIN) |
(3U << 2U*TST4_PIN) | (3U << 2U*TST5_PIN) | (3U << 2U*TST6_PIN) |
(3U << 2U*TST7_PIN));
// enable GPIOC clock port for the Button B1
RCC->IOPENR |= (1U << 2U);
// configure Button B1 pin on GPIOC as input, no pull-up, pull-down
GPIOC->MODER &= ~(3U << 2U*B1_PIN);
GPIOC->PUPDR &= ~(3U << 2U*B1_PIN);
}
//............................................................................
void BSP_start(void) {
// instantiate and start QP/C active objects...
Periodic1_ctor();
static QEvtPtr periodic1QSto[10]; // Event queue storage
QActive_start(
AO_Periodic1, // AO pointer to start
1U, // QF-prio
periodic1QSto, // storage for the AO's queue
Q_DIM(periodic1QSto), // queue length
(void *)0, 0U, // stack storage, size (not used)
BSP_getEvtPeriodic1(0U)); // initialization param
Sporadic2_ctor();
static QEvtPtr sporadic2QSto[8]; // Event queue storage
QActive_start(
AO_Sporadic2, // AO pointer to start
2U, // QF-prio
sporadic2QSto, // storage for the AO's queue
Q_DIM(sporadic2QSto), // queue length
(void *)0, 0U, // stack storage, size (not used)
(void const *)0); // initialization param -- not used
Sporadic3_ctor();
static QEvtPtr sporadic3QSto[8]; // Event queue storage
QActive_start(
AO_Sporadic3, // AO pointer to start
3U, // QF-prio
sporadic3QSto, // storage for the AO's queue
Q_DIM(sporadic3QSto), // queue length
(void *)0, 0U, // stack storage, size (not used)
(void const *)0); // initialization param -- not used
Periodic4_ctor();
static QEvtPtr periodic4QSto[8]; // Event queue storage
QActive_start(
AO_Periodic4, // AO pointer to start
4U, // QF-prio
periodic4QSto, // storage for the AO's queue
Q_DIM(periodic4QSto), // queue length
(void *)0, 0U, // stack storage, size (not used)
BSP_getEvtPeriodic4(0U)); // initialization event
}
//............................................................................
void BSP_d1on(void) { GPIOA->BSRR = (1U << TST1_PIN); }
void BSP_d1off(void) { GPIOA->BSRR = (1U << (TST1_PIN + 16U)); }
//............................................................................
void BSP_d2on(void) { GPIOA->BSRR = (1U << TST2_PIN); }
void BSP_d2off(void) { GPIOA->BSRR = (1U << (TST2_PIN + 16U)); }
//............................................................................
void BSP_d3on(void) { GPIOA->BSRR = (1U << TST3_PIN); }
void BSP_d3off(void) { GPIOA->BSRR = (1U << (TST3_PIN + 16U)); }
//............................................................................
void BSP_d4on(void) { GPIOA->BSRR = (1U << TST4_PIN); }
void BSP_d4off(void) { GPIOA->BSRR = (1U << (TST4_PIN + 16U)); }
//............................................................................
void BSP_d5on(void) { GPIOA->BSRR = (1U << TST5_PIN); }
void BSP_d5off(void) { GPIOA->BSRR = (1U << (TST5_PIN + 16U)); }
//............................................................................
void BSP_d6on(void) { GPIOA->BSRR = (1U << TST6_PIN); } // LED2
void BSP_d6off(void) { GPIOA->BSRR = (1U << (TST6_PIN + 16U)); }
//............................................................................
void BSP_d7on(void) { GPIOA->BSRR = (1U << TST7_PIN); }
void BSP_d7off(void) { GPIOA->BSRR = (1U << (TST7_PIN + 16U)); }
//............................................................................
QEvt const *BSP_getEvtPeriodic1(uint8_t num) {
// immutable PERIODIC_SPEC events for Periodic1
static PeriodicSpecEvt const periodicSpec1[] = {
{
QEVT_INITIALIZER(PERIODIC_SPEC_SIG),
.toggles = 40U,
.ticks = 5U,
},
{
QEVT_INITIALIZER(PERIODIC_SPEC_SIG),
.toggles = 30U,
.ticks = 7U,
}
};
Q_REQUIRE_ID(500, num < Q_DIM(periodicSpec1)); // must be in range
return &periodicSpec1[num].super;
}
//............................................................................
QEvt const *BSP_getEvtPeriodic4(uint8_t num) {
// immutable PERIODIC_SPEC events for Periodic4
static PeriodicSpecEvt const periodicSpec4[] = {
{
QEVT_INITIALIZER(PERIODIC_SPEC_SIG),
.toggles = 20U,
.ticks = 2U,
},
{
QEVT_INITIALIZER(PERIODIC_SPEC_SIG),
.toggles = 10U,
.ticks = 1U,
},
};
Q_REQUIRE_ID(600, num < Q_DIM(periodicSpec4)); // must be in range
return &periodicSpec4[num].super;
}
// QF callbacks ==============================================================
void QF_onStartup(void) {
SystemCoreClockUpdate();
// set up the SysTick timer to fire at BSP_TICKS_PER_SEC rate
SysTick_Config((SystemCoreClock / BSP_TICKS_PER_SEC) + 1U);
// set priorities of ISRs used in the system
// NOTE: all interrupts are "kernel aware" in Cortex-M0+
NVIC_SetPriority(SysTick_IRQn, 0U);
// ...
}
//............................................................................
void QF_onCleanup(void) {
}
//............................................................................
#ifdef QF_ON_CONTEXT_SW
// NOTE: the context-switch callback is called with interrupts DISABLED
void QF_onContextSw(QActive *prev, QActive *next) {
}
#endif // QF_ON_CONTEXT_SW
//............................................................................
void QV_onIdle(void) { // CAUTION: called with interrupts DISABLED, see NOTE0
BSP_d7on(); // LED LD2
#ifdef NDEBUG
// Put the CPU and peripherals to the low-power mode.
// you might need to customize the clock management for your application,
// see the datasheet for your particular Cortex-M MCU.
//
QV_CPU_SLEEP(); // atomically go to sleep and enable interrupts
#else
QF_INT_ENABLE(); // just enable interrupts
#endif
BSP_d7off();
}
//============================================================================
// NOTE0:
// The QV_onIdle() callback is called with interrupts disabled, because the
// determination of the idle condition might change by any interrupt posting
// an event. QV_onIdle() must internally enable interrupts, ideally
// atomically with putting the CPU to the power-saving mode.
//