///*************************************************************************** // 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 . // // Contact information: // http://www.state-machine.com // mailto:info@state-machine.com //**************************************************************************** //#include #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 //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