/*****************************************************************************
* Product: DPP on AT91SAM7S-EK board, cooperative QV kernel
* Last Updated for Version: 5.5.1
* Date of the Last Update: 2015-10-05
*
* Q u a n t u m L e a P s
* ---------------------------
* innovating embedded systems
*
* Copyright (C) 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
* along with this program. If not, see .
*
* Contact information:
*
*
*****************************************************************************/
#include "qpn.h"
#include "dpp.h"
#include "bsp.h"
#include "AT91SAM7S64.h" /* Atmel AT91SAM7S64 MCU */
//Q_DEFINE_THIS_FILE
#pragma diag_suppress=Ta021 /* call __iar_disable_interrupt from __ramfunc */
#pragma diag_suppress=Ta022 /* possible ROM access from __ramfunc */
#pragma diag_suppress=Ta023 /* call to non __ramfunc from __ramfunc */
/* Local objects -----------------------------------------------------------*/
typedef void (*IntVector)(void); /* IntVector pointer-to-function */
uint32_t get_MCK_FREQ(void); /* CPU clock set up in __low_level_init() */
uint32_t const l_led[] = {
(1U << 0), /* LED D1 on AT91SAM7S-EK */
(1U << 1), /* LED D2 on AT91SAM7S-EK */
(1U << 2), /* LED D3 on AT91SAM7S-EK */
(1U << 3) /* LED D4 on AT91SAM7S-EK */
};
#define LED_ON(num_) (AT91C_BASE_PIOA->PIO_CODR = l_led[num_])
#define LED_OFF(num_) (AT91C_BASE_PIOA->PIO_SODR = l_led[num_])
uint32_t const l_btn[] = {
(1U << 19), /* BTN P1 on AT91SAM7S-EK */
(1U << 20), /* BTN P2 on AT91SAM7S-EK */
(1U << 14), /* BTN P3 on AT91SAM7S-EK */
(1U << 15) /* BTN P4 on AT91SAM7S-EK */
};
/* random seed */
static uint32_t l_rnd;
/* ISRs and ISR "wrappers" ================================================*/
__ramfunc
void BSP_irq(void) {
IntVector vect = (IntVector)AT91C_BASE_AIC->AIC_IVR; /* read the IVR */
AT91C_BASE_AIC->AIC_IVR = (AT91_REG)vect; /* write AIC_IVR if protected */
QF_INT_ENABLE(); /* allow nesting interrupts */
(*vect)(); /* call the IRQ ISR via the pointer to function */
QF_INT_DISABLE(); /* disable interrups for the exit sequence */
AT91C_BASE_AIC->AIC_EOICR = 0; /* write AIC_EOICR to clear interrupt */
}
/* ISRs --------------------------------------------------------------------*/
__ramfunc
static void ISR_tick(void) {
/* state of the button debouncing, see below */
static struct ButtonsDebouncing {
uint32_t depressed;
uint32_t previous;
} buttons = { ~0U, ~0U };
uint32_t current;
uint32_t volatile tmp;
/* clear the interrupt source */
tmp = AT91C_BASE_PITC->PITC_PIVR;
QF_tickXISR(0U); /* process time events for 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.
*/
current = ~AT91C_BASE_PIOA->PIO_PDSR;/* read PIOA with state of Buttons */
tmp = buttons.depressed; /* save the debounced 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 */
if ((tmp & l_btn[0]) != 0U) { /* debounced BTN_P1 state changed? */
if ((buttons.depressed & l_btn[0]) != 0U) { /* is BTN_P1 depressed? */
QACTIVE_POST_ISR(&AO_Table, PAUSE_SIG, 0U);
}
else { /* the button is released */
QACTIVE_POST_ISR(&AO_Table, SERVE_SIG, 0U);
}
}
}
/*..........................................................................*/
__ramfunc
static void ISR_spur(void) {
}
/* BSP functions ===========================================================*/
void BSP_init(void) {
uint32_t i;
/* When using the JTAG debugger the AIC might not be initialised
* to the correct default state. This line ensures that AIC does not
* mask all interrupts at the start.
*/
AT91C_BASE_AIC->AIC_EOICR = 0U;
/* enable peripheral clock for PIOA */
AT91C_BASE_PMC->PMC_PCER = (1U << AT91C_ID_PIOA);
/* initialize the LEDs... */
for (i = 0; i < Q_DIM(l_led); ++i) {
AT91C_BASE_PIOA->PIO_PER = l_led[i]; /* enable pin */
AT91C_BASE_PIOA->PIO_OER = l_led[i]; /* configure as output pin */
LED_OFF(i); /* extinguish the LED */
}
/* initialize the Buttons... */
for (i = 0; i < Q_DIM(l_btn); ++i) {
AT91C_BASE_PIOA->PIO_ODR = l_btn[i]; /* disable output (input pin) */
AT91C_BASE_PIOA->PIO_PER = l_btn[i]; /* enable pin */
}
/* configure Advanced Interrupt Controller (AIC) of AT91... */
AT91C_BASE_AIC->AIC_IDCR = ~0; /* disable all interrupts */
AT91C_BASE_AIC->AIC_ICCR = ~0; /* clear all interrupts */
for (i = 0; i < 8; ++i) {
AT91C_BASE_AIC->AIC_EOICR = 0; /* write AIC_EOICR 8 times */
}
/* set the desired ticking rate for the PIT... */
i = (get_MCK_FREQ() / 16U / BSP_TICKS_PER_SEC) - 1U;
AT91C_BASE_PITC->PITC_PIMR = (AT91C_PITC_PITEN | AT91C_PITC_PITIEN | i);
BSP_randomSeed(1234U); /* seed the random number generator */
}
/*..........................................................................*/
void BSP_displayPhilStat(uint8_t n, char const *stat) {
if (stat[0] == 'h') {
LED_ON(0); /* turn LED on */
}
else {
LED_OFF(0); /* turn LED off */
}
if (stat[0] == 'e') {
LED_ON(1); /* turn LED on */
}
else {
LED_OFF(1); /* turn LED off */
}
}
/*..........................................................................*/
void BSP_displayPaused(uint8_t paused) {
if (paused != (uint8_t)0) {
LED_ON(2); /* turn LED on */
}
else {
LED_OFF(2); /* turn LED off */
}
}
/*..........................................................................*/
uint32_t BSP_random(void) { /* a very cheap pseudo-random-number generator */
/* "Super-Duper" Linear Congruential Generator (LCG)
* LCG(2^32, 3*7*11*13*23, 0, seed)
*/
l_rnd = l_rnd * (3U*7U*11U*13U*23U);
return l_rnd >> 8;
}
/*..........................................................................*/
void BSP_randomSeed(uint32_t seed) {
l_rnd = seed;
}
/*..........................................................................*/
void BSP_terminate(int16_t result) {
(void)result;
}
/* QF callbacks ============================================================*/
void QF_onStartup(void) {
/* hook the exception handlers from the QF port... */
*(uint32_t volatile *)0x24 = (uint32_t)&QF_undef;
*(uint32_t volatile *)0x28 = (uint32_t)&QF_swi;
*(uint32_t volatile *)0x2C = (uint32_t)&QF_pAbort;
*(uint32_t volatile *)0x30 = (uint32_t)&QF_dAbort;
*(uint32_t volatile *)0x34 = (uint32_t)&QF_reserved;
*(uint32_t volatile *)0x38 = (uint32_t)&QV_irq;
*(uint32_t volatile *)0x3C = (uint32_t)0; /* QV_fiq unimplemented! */
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (uint32_t)&ISR_tick;
AT91C_BASE_AIC->AIC_SPU = (uint32_t)&ISR_spur; /* spurious IRQ */
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] =
(AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST);
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SYS);
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_SYS);
}
/*..........................................................................*/
__ramfunc
void QV_onIdle(void) { /* NOTE: called with interrupts DISABLED */
/* toggle first LED on and off, see NOTE01 */
LED_ON(3); /* turn LED on */
LED_OFF(3); /* turn LED off */
#ifdef NDEBUG /* only if not debugging (idle mode hinders debugging) */
AT91C_BASE_PMC->PMC_SCDR = 1;/* Power-Management: disable the CPU clock */
/* NOTE: an interrupt starts the CPU clock again */
QF_INT_ENABLE(); /* enable interrupts as soon as CPU clock starts */
#else
QF_INT_ENABLE();
#endif
}
/*..........................................................................*/
Q_NORETURN Q_onAssert(char const Q_ROM * const module, int loc) {
QF_INT_DISABLE(); /* disable all interrupts */
/*
* NOTE: add here your application-specific error handling
*/
(void)module;
(void)loc;
/* trip the Watchdog to reset the system */
AT91C_BASE_WDTC->WDTC_WDCR = (0xA5U << 24) | AT91C_WDTC_WDRSTT;
/* hang in here until the reset occurrs */
for (;;) {
}
}
/*****************************************************************************
* NOTE01:
* One of the LEDs is used to visualize the idle loop activity. The brightness
* of the LED is proportional to the frequency of invcations of the idle loop.
* Please note that the LED is toggled with interrupts locked, so no interrupt
* execution time contributes to the brightness of the User LED.
*/