seesaw/source/bsp.cpp
2018-10-02 14:15:38 -04:00

344 lines
8.6 KiB
C++

///***************************************************************************
// Product: DPP example, STM32 NUCLEO-L152RE board, preemptive QK kernel
// Last updated for version 5.6.5
// Last updated on 2016-07-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 <http://www.gnu.org/licenses/>.
//
// Contact information:
// http://www.state-machine.com
// mailto:info@state-machine.com
//****************************************************************************
//#include <string.h>
#include "qpcpp.h"
#include "bsp.h"
#include "bsp_nvmctrl.h"
#include "sam.h"
#include "bsp_gpio.h"
#include "bsp_sercom.h"
#include "bsp_neopix.h"
#include "bsp_adc.h"
#include "SeesawConfig.h"
#include "Delegate.h"
#include <stdlib.h>
//Q_DEFINE_THIS_FILE
#define ENABLE_BSP_PRINT
volatile uint32_t lastGPIOState = 0;
volatile uint32_t _systemMs = 0;
void operator delete(void * p)
{
free(p);
}
void * operator new(size_t n)
{
void * const p = malloc(n);
// handle p == 0
//if(p == 0) __BKPT();
return p;
}
void BspInit() {
//initialize some clocks
#if defined(SAMD21)
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ;
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 ;
#else
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_TC1 | PM_APBCMASK_TC2;
#endif
#ifdef TCC0
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 ;
#endif
#ifdef SERCOM2
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM2 ;
#endif
#ifdef DAC
PM->APBCMASK.reg |= PM_APBCMASK_ADC | PM_APBCMASK_DAC ;
#endif
#if CONFIG_EEPROM
eeprom_init();
#endif
/*
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCLK_CLKCTRL_ID_EIC_Val));
// Enable EIC
EIC->CTRL.bit.ENABLE = 1;
while (EIC->STATUS.bit.SYNCBUSY == 1) { }
*/
#ifdef ENABLE_LOGGING
pinPeripheral(CONFIG_LOG_UART_PIN_TX, CONFIG_LOG_UART_PIN_TX_MUX);
initUART(CONFIG_LOG_SERCOM, SAMPLE_RATE_x16, CONFIG_LOG_UART_BAUD_RATE);
initFrame(CONFIG_LOG_SERCOM, CONFIG_LOG_UART_CHAR_SIZE, LSB_FIRST, CONFIG_LOG_UART_PARITY, CONFIG_LOG_UART_STOP_BIT);
initPads(CONFIG_LOG_SERCOM, CONFIG_LOG_UART_PAD_TX, CONFIG_LOG_UART_PAD_RX);
enableUART(CONFIG_LOG_SERCOM);
#endif
}
void BspWrite(char const *buf, uint32_t len) {
//TODO:
}
uint32_t GetSystemMs() {
return _systemMs;
}
extern "C" {
void SysTick_Handler(void) {
QXK_ISR_ENTRY();
QP::QF::tickX_(0);
_systemMs++;
//process GPIO interrupts
uint32_t GPIOState = gpio_read_bulk();
if( (Delegate::m_inten & GPIOState) != (Delegate::m_inten & lastGPIOState) ){
Delegate::m_intflag |= GPIOState ^ lastGPIOState;
Delegate::intCallback();
}
lastGPIOState = GPIOState;
#if defined(SAMD21)
tickReset();
#endif
QXK_ISR_EXIT();
}
#if defined(SAMD21)
static void (*usb_isr)(void) = NULL;
void USB_Handler(void)
{
if (usb_isr)
usb_isr();
}
void USB_SetHandler(void (*new_usb_isr)(void))
{
usb_isr = new_usb_isr;
}
#endif
}
// namespace QP **************************************************************
namespace QP {
// QF callbacks ==============================================================
void QF::onStartup(void) {
// assigning all priority bits for preemption-prio. and none to sub-prio.
//NVIC_SetPriorityGrouping(0U);
NVIC_SetPriority(PendSV_IRQn, 0xFF);
SysTick_Config(SystemCoreClock / BSP_TICKS_PER_SEC);
NVIC_SetPriority(SysTick_IRQn, SYSTICK_PRIO);
#if CONFIG_I2C_SLAVE
NVIC_SetPriority(CONFIG_I2C_SLAVE_IRQn, I2C_SLAVE_ISR_PRIO);
#endif
#if CONFIG_SPI_SLAVE
NVIC_SetPriority(CONFIG_SPI_SLAVE_IRQn, SPI_SLAVE_ISR_PRIO);
#endif
#if defined(SAMD21)
NVIC_SetPriority(USB_IRQn, USB_ISR_PRIO);
#endif
//NVIC_SetPriority(NVMCTRL_IRQn, NVMCTRL_ISR_PRIO);
#if defined(SERCOM0)
NVIC_SetPriority(SERCOM0_IRQn, SERCOM_ISR_PRIO);
#endif
#if defined(SERCOM1)
NVIC_SetPriority(SERCOM1_IRQn, SERCOM_ISR_PRIO);
#endif
#if defined(SERCOM2)
NVIC_SetPriority(SERCOM2_IRQn, SERCOM_ISR_PRIO);
#endif
#if defined(SERCOM5)
NVIC_SetPriority(SERCOM5_IRQn, SERCOM_ISR_PRIO);
#endif
#if CONFIG_ENCODER
NVIC_SetPriority(CONFIG_ENCODER_IRQn, ENCODER_ISR_PRIO);
#endif
// set priorities of ALL ISRs used in the system, see NOTE00
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Assign a priority to EVERY ISR explicitly by calling NVIC_SetPriority().
// DO NOT LEAVE THE ISR PRIORITIES AT THE DEFAULT VALUE!
//NVIC_SetPriority(EXTI0_1_IRQn, DPP::EXTI0_1_PRIO);
// ...
// enable IRQs...
NVIC_EnableIRQ(SysTick_IRQn);
//NVIC_EnableIRQ(NVMCTRL_IRQn);
#if CONFIG_I2C_SLAVE
NVIC_EnableIRQ(CONFIG_I2C_SLAVE_IRQn);
#endif
#if CONFIG_SPI_SLAVE
NVIC_EnableIRQ(CONFIG_SPI_SLAVE_IRQn);
#endif
#if CONFIG_SERCOM0
NVIC_EnableIRQ(SERCOM0_IRQn);
#endif
#if CONFIG_SERCOM1
NVIC_EnableIRQ(SERCOM1_IRQn);
#endif
#if CONFIG_SERCOM2
NVIC_EnableIRQ(SERCOM2_IRQn);
#endif
#if CONFIG_SERCOM5
NVIC_EnableIRQ(SERCOM5_IRQn);
#endif
#if CONFIG_USB
NVIC_EnableIRQ(USB_IRQn);
#endif
#if CONFIG_ENCODER
NVIC_EnableIRQ(CONFIG_ENCODER_IRQn);
#endif
}
//............................................................................
void QF::onCleanup(void) {
}
//............................................................................
void QXK::onIdle(void) {
// toggle the User LED on and then off (not enough LEDs, see NOTE01)
//QF_INT_DISABLE();
//QF_INT_ENABLE();
// 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-M3 MCU.
//
// !!!CAUTION!!!
// The WFI instruction stops the CPU clock, which unfortunately disables
// the JTAG port, so the ST-Link debugger can no longer connect to the
// board. For that reason, the call to __WFI() has to be used with CAUTION.
//
// NOTE: If you find your board "frozen" like this, strap BOOT0 to VDD and
// reset the board, then connect with ST-Link Utilities and erase the part.
// The trick with BOOT(0) is it gets the part to run the System Loader
// instead of your broken code. When done disconnect BOOT0, and start over.
//
__WFI(); // Wait-For-Interrupt
}
//............................................................................
extern "C" void Q_onAssert(char const * const module, int loc) {
//
// NOTE: add here your application-specific error handling
//
QF_INT_DISABLE();
#ifdef ENABLE_LOGGING
char __ms[50];
sprintf(__ms, "[%li] ***QASSERT**** ", GetSystemMs());
writeDataUART(CONFIG_LOG_SERCOM, __ms);
writeDataUART(CONFIG_LOG_SERCOM, module);
sprintf(__ms, " at %i", loc);
writeDataUART(CONFIG_LOG_SERCOM, __ms);
#endif
__BKPT();
while(1);
}
extern "C" void assert_failed(char const *module, int loc) {
__BKPT();
while(1);
}
#if defined(SAMD21)
#ifdef __cplusplus
extern "C" {
#endif
static void banzai() {
// Disable all interrupts
__disable_irq();
//THESE MUST MATCH THE BOOTLOADER
#define DOUBLE_TAP_MAGIC 0xf01669efUL
#define BOOT_DOUBLE_TAP_ADDRESS (HMCRAMC0_ADDR + HMCRAMC0_SIZE - 4)
unsigned long *a = (unsigned long *)BOOT_DOUBLE_TAP_ADDRESS;
*a = DOUBLE_TAP_MAGIC;
// Reset the device
NVIC_SystemReset() ;
while (true);
}
static int ticks = -1;
void initiateReset(int _ticks) {
ticks = _ticks;
}
void cancelReset() {
ticks = -1;
}
void tickReset() {
if (ticks == -1)
return;
ticks--;
if (ticks == 0)
banzai();
}
#ifdef __cplusplus
}
#endif
#endif
} // namespace QP