You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
13 KiB
C

//============================================================================
// 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 "TM4C123GH6PM.h" /* the device specific header (TI) */
/* add other drivers if necessary... */
Q_DEFINE_THIS_FILE // define the name of this file for assertions
/* Local-scope defines -----------------------------------------------------*/
/* test pins on GPIOF */
#define TST1_PIN (1U << 1U) /* LED Red */
#define TST3_PIN (1U << 2U) /* LED Blue */
#define TST7_PIN (1U << 3U) /* LED Green */
/* test pins on GPIOD */
#define TST4_PIN (1U << 0U)
#define TST5_PIN (1U << 1U)
#define TST6_PIN (1U << 2U)
/* Buttons on GPIOF */
#define BTN_SW1 (1U << 4)
#define BTN_SW2 (1U << 0)
//============================================================================
// 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
GPIOF_AHB->DATA_Bits[TST1_PIN | TST3_PIN | TST7_PIN] = 0xFFU; /* all 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 };
/* read SW1 & SW2 */
uint32_t current = ~GPIOF_AHB->DATA_Bits[BTN_SW1 | BTN_SW2];
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 & BTN_SW1) != 0U) { /* debounced SW1 state changed? */
if ((buttons.depressed & BTN_SW1) != 0U) { /* is SW1 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 { /* the button 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) {
/* enable clock for to the peripherals used by this application... */
SYSCTL->RCGCGPIO |= (1U << 5U); /* enable Run mode for GPIOF */
SYSCTL->RCGCGPIO |= (1U << 3U); /* enable Run mode for GPIOD */
SYSCTL->GPIOHBCTL |= (1U << 5U); /* enable AHB for GPIOF */
SYSCTL->GPIOHBCTL |= (1U << 3U); /* enable AHB for GPIOD */
__ISB();
__DSB();
/* configure test pins on GPIOF (digital output) */
GPIOF_AHB->DIR |= (TST1_PIN | TST3_PIN | TST7_PIN);
GPIOF_AHB->DEN |= (TST1_PIN | TST3_PIN | TST7_PIN);
/* configure button on GPIOF (digital input) */
GPIOF_AHB->DIR &= ~(BTN_SW1); /* input */
GPIOF_AHB->DEN |= (BTN_SW1); /* digital enable */
GPIOF_AHB->PUR |= (BTN_SW1); /* pull-up resistor enable */
/* configure test pins on GPIOD (digital output) */
GPIOD_AHB->DIR |= (TST4_PIN | TST5_PIN | TST6_PIN);
GPIOD_AHB->DEN |= (TST4_PIN | TST5_PIN | TST6_PIN);
/* configure switches... */
/* unlock access to the SW2 pin because it is PROTECTED */
GPIOF_AHB->LOCK = 0x4C4F434BU; /* unlock GPIOCR register for SW2 */
/* commit the write (cast const away) */
*(uint32_t volatile *)&GPIOF_AHB->CR = 0x01U;
GPIOF_AHB->DIR &= ~(BTN_SW1 | BTN_SW2); /* input */
GPIOF_AHB->DEN |= (BTN_SW1 | BTN_SW2); /* digital enable */
GPIOF_AHB->PUR |= (BTN_SW1 | BTN_SW2); /* pull-up resistor enable */
*(uint32_t volatile *)&GPIOF_AHB->CR = 0x00U;
GPIOF_AHB->LOCK = 0x0; /* lock GPIOCR register for SW2 */
}
//............................................................................
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
}
//............................................................................
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) {
/* NOTE: SystemInit() has been already called from the startup code
* but SystemCoreClock needs to be updated
*/
SystemCoreClockUpdate();
/* set up the SysTick timer to fire at BSP_TICKS_PER_SEC rate
* NOTE: do NOT call OS_CPU_SysTickInit() from uC/OS-II
*/
SysTick_Config(SystemCoreClock / BSP_TICKS_PER_SEC);
/* set priorities of ALL ISRs used in the system, see NOTE1 */
NVIC_SetPriority(SysTick_IRQn, QF_AWARE_ISR_CMSIS_PRI + 1U);
/* ... */
/* enable IRQs in the NVIC... */
/* ... */
}
/*..........................................................................*/
void BSP_d1on(void) { /* LED-Red */
GPIOF_AHB->DATA_Bits[TST1_PIN] = 0xFFU;
/* don't use the FPU in the ISR */
}
void BSP_d1off(void) {
GPIOF_AHB->DATA_Bits[TST1_PIN] = 0x00U;
}
/*..........................................................................*/
void BSP_d3on(void) { /* LED-Blue */
GPIOF_AHB->DATA_Bits[TST3_PIN] = 0xFFU;
}
void BSP_d3off(void) {
GPIOF_AHB->DATA_Bits[TST3_PIN] = 0x00U;
}
/*..........................................................................*/
void BSP_d4on(void) {
GPIOD_AHB->DATA_Bits[TST4_PIN] = 0xFFU;
}
void BSP_d4off(void) {
GPIOD_AHB->DATA_Bits[TST4_PIN] = 0x00U;
}
/*..........................................................................*/
void BSP_d5on(void) {
GPIOD_AHB->DATA_Bits[TST5_PIN] = 0xFFU;
}
void BSP_d5off(void) {
GPIOD_AHB->DATA_Bits[TST5_PIN] = 0x00U;
}
/*..........................................................................*/
void BSP_d6on(void) {
GPIOD_AHB->DATA_Bits[TST6_PIN] = 0xFFU;
}
void BSP_d6off(void) {
GPIOD_AHB->DATA_Bits[TST6_PIN] = 0x00U;
}
/*..........................................................................*/
void BSP_d7on(void) { /* LED2-Green */
GPIOF_AHB->DATA_Bits[TST7_PIN] = 0xFFU;
}
void BSP_d7off(void) {
GPIOF_AHB->DATA_Bits[TST7_PIN] = 0x00U;
}
//............................................................................
void QF_onCleanup(void) {
}
//............................................................................
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.
//