188 lines
7.2 KiB
C++
Raw Normal View History

//============================================================================
2019-06-18 16:56:56 -04:00
// BSP for Blinky example, Microstick II board, cooperative QV kernel, XC32
// Last updated for version 6.5.1
// Last updated on 2019-06-10
//
// Q u a n t u m L e a P s
// ------------------------
// Modern Embedded Software
//
// Copyright (C) 2005-2019 Quantum Leaps, LLC. All rights reserved.
//
// This program is open source software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Alternatively, this program may be distributed and modified under the
// terms of Quantum Leaps commercial licenses, which expressly supersede
// the GNU General Public License and are specifically designed for
// licensees interested in retaining the proprietary status of their code.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
2019-12-31 15:56:23 -05:00
// along with this program. If not, see <www.gnu.org/licenses/>.
2019-06-18 16:56:56 -04:00
//
// Contact information:
2019-12-31 15:56:23 -05:00
// <www.state-machine.com/licensing>
// <info@state-machine.com>
//============================================================================
2019-10-27 12:26:31 -04:00
#include "qpcpp.hpp"
#include "bsp.hpp"
#include "blinky.hpp"
2019-06-18 16:56:56 -04:00
Q_DEFINE_THIS_FILE
#ifdef Q_SPY
#error Simple Blinky Application does not provide Spy build configuration
#endif
#pragma config FNOSC = FRCPLL // 8 MHz
#pragma config FPLLIDIV = DIV_2 // 4 MHz
#pragma config FPLLMUL = MUL_20 // 80 MHz
#pragma config FPLLODIV = DIV_2 // 40 MHz == FRC
#pragma config FWDTEN = OFF // watchdog off
#pragma config FPBDIV = DIV_1 // same peripheral clock
// #pragma config statements should precede project file includes
#include <xc.h> // header for PIC32 device in use
#include <sys/attribs.h>
// system clock using FRC and PLL: 40 MHz
#define SYS_FREQ 40000000U
// peripheral clock frequency
#define PER_HZ (SYS_FREQ / 1U)
// controlling the LED of Microstick II
#define LED_ON() (LATASET = (1U << 0))
#define LED_OFF() (LATACLR = (1U << 0))
#define LED_TOGGLE() (LATAINV = (1U << 0))
// namespace DPP *************************************************************
namespace DPP {
// Local-scope objects -------------------------------------------------------
// ISRs used in this project =================================================
extern "C" {
void __ISR(_TIMER_2_VECTOR, IPL4SOFT) tickISR(void) {
IFS0CLR = _IFS0_T2IF_MASK; // clear the interrupt source
2022-08-11 15:36:19 -04:00
QP::QTimeEvt::TICK_X(0U, nullptr); // handle armed time events at tick rate 0
2019-06-18 16:56:56 -04:00
}
//............................................................................
// for testing interrupt nesting and active object preemption
void __ISR(_EXTERNAL_0_VECTOR, IPL6SOFT) testISR(void) {
static QP::QEvt const tout_evt = { TIMEOUT_SIG, 0U, 0U };
IFS0CLR = _IFS0_INT0IF_MASK; // clear the interrupt source
2020-04-02 21:21:53 -04:00
AO_Blinky->POST(&tout_evt, nullptr);
2019-06-18 16:56:56 -04:00
}
} // extern "C"
} // namespace DPP
// BSP functions =============================================================
void BSP_init(void) {
TRISA = 0x00; // set LED pins as outputs
PORTA = 0x00; // set LED drive state low
}
//............................................................................
void BSP_terminate(int16_t result) {
(void)result;
}
//............................................................................
void BSP_ledOff(void) {
LED_OFF();
}
//............................................................................
void BSP_ledOn(void) {
LED_ON();
}
//............................................................................
// NOTE: this implementation of the assertion 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).
//
extern "C"
2020-03-17 21:33:58 -04:00
Q_NORETURN Q_onAssert(char const * const file, int_t const loc) {
2019-06-18 16:56:56 -04:00
(void)file; // unused parameter
2019-12-31 15:56:23 -05:00
(void)loc; // unused parameter
2019-06-18 16:56:56 -04:00
QF_INT_DISABLE(); // make sure that interrupts are disabled
for (;;) {
}
}
// namespace QP **************************************************************
namespace QP {
// QF callbacks ==============================================================
void QF::onStartup(void) { // entered with interrupts disabled
INTCONSET = _INTCON_MVEC_MASK; // configure multi-vectored interrupts
T2CON = 0x0060; // stop timer, set up for 1:64 prescaler
TMR2 = 0; // count from zero up to the period
PR2 = SYS_FREQ / (BSP_TICKS_PER_SEC * 64); // set the Timer2 period
IFS0CLR = _IFS0_T2IF_MASK; // clear Timer2 Interrupt Flag
IEC0SET = _IEC0_T2IE_MASK; // enable Timer2 interrupt
T2CONSET = _T2CON_ON_MASK; // Start Timer2
INTCONbits.INT0EP = 1; // INT0 interrupt on positive edge
IEC0SET = _IEC0_INT0IE_MASK; // enable INT0 interrupt
IFS0CLR = _IFS0_INT0IF_MASK; // clear the interrupt for INT0
// explicitly assign priorities to all interrupts...
// NOTE: must match the IPLxSOFT settings in the __ISR() macros
IPC2bits.T2IP = 4; // Timer2 interrupt priority, must match tickISR
IPC0bits.INT0IP = 6; // set INT0 priority; must match IPL in testISR
}
//............................................................................
void QF::onCleanup(void) {
}
//............................................................................
void QV::onIdle(void) { // NOTE: called with interrupts disabled
// NOTE: not enough LEDs on the Microstick II board to implement
// the idle loop activity indicator ...
//LED_ON (); /* blink the IDLE LED
//LED_OFF();
#ifdef NDEBUG
INTCONbits.TPC = 7; // enable the Proximity Timer for all IPLs, NOTE01
IPTMR = 4; // set the proximity timer to 4 CPU clocks, see NOTE02
QF_INT_ENABLE(); // enable CPU interrupts
_wait(); // execute the WAIT instruction to stop the CPU
INTCONbits.TPC = 0; // disable the Proximity Timer for all IPLs, NOTE01
#else
QF_INT_ENABLE(); // just enable interrupts, see NOTE01
#endif
}
} // namespace QP
//============================================================================
2019-06-18 16:56:56 -04:00
// NOTE01:
// The callback function QV::onIdle() is called with interrupts disabled,
// because the idle condition can be invalidated by any enabled interrupt
// that would post events. The QV::onIdle() function *must* re-enable interrupts
// internally
//
// NOTE02:
// The Temporal Proximity Timer is used to prevent a race condition of
// servicing an interrupt after re-enabling interrupts and before executing
// the WAIT instruction. The Proximity Timer is enabled for all interrupt
// priority levels (see QF::onStartup()). The Proximity Timer is set to 4
// CPU clocks right before re-enabling interrupts (with the DI instruction)
// The 4 clock ticks should be enough to execute the (DI,WAIT) instruction
// pair _atomically_.
//