From 8d9c3cc2b74f5b8a3f765d2d6e901ee6c0abc987 Mon Sep 17 00:00:00 2001 From: etagle Date: Wed, 11 Oct 2017 03:33:19 -0300 Subject: [PATCH] Add a module for Due SRAM-based Interrupt Vector Table This is the ONLY way to be able to override ISRs stolen by the Arduino Runtime, such as Serial or USB device interrupts. This feature is needed so Arduino modules can be replaced and enhanced. --- .../src/HAL/HAL_DUE/InterruptVectors_Due.cpp | 95 +++++++++++++++++++ Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.h | 52 ++++++++++ 2 files changed, 147 insertions(+) create mode 100644 Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.cpp create mode 100644 Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.h diff --git a/Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.cpp b/Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.cpp new file mode 100644 index 0000000000..0a46776110 --- /dev/null +++ b/Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.cpp @@ -0,0 +1,95 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free 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. + * + * 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 . + * + */ + +/** + * InterruptVectors_Due.cpp - This module relocates the Interrupt vector table to SRAM, + * allowing to register new interrupt handlers at runtime. Specially valuable and needed + * because Arduino runtime allocates some interrupt handlers that we NEED to override to + * properly support extended functionality, as for example, USB host or USB device (MSD, MTP) + * and custom serial port handlers, and we don't actually want to modify and/or recompile the + * Arduino runtime. We just want to run as much as possible on Stock Arduino + * + * Copyright (c) 2017 Eduardo José Tagle. All right reserved + */ +#ifdef ARDUINO_ARCH_SAM + +#include "HAL_Due.h" +#include "InterruptVectors_Due.h" + +/* The relocated Exception/Interrupt Table - Must be aligned to 128bytes, + as bits 0-6 on VTOR register are reserved and must be set to 0 */ +__attribute__ ((aligned(128))) +static DeviceVectors ram_tab = { NULL }; + +/** + * This function checks if the exception/interrupt table is already in SRAM or not. + * If it is not, then it copies the ROM table to the SRAM and relocates the table + * by reprogramming the NVIC registers + */ +static pfnISR_Handler* get_relocated_table_addr(void) { + // Get the address of the interrupt/exception table + uint32_t isrtab = SCB->VTOR; + + // If already relocated, we are done! + if (isrtab >= IRAM0_ADDR) + return (pfnISR_Handler*)isrtab; + + // Get the address of the table stored in FLASH + const pfnISR_Handler* romtab = (const pfnISR_Handler*)isrtab; + + // Copy it to SRAM + memcpy(&ram_tab, romtab, sizeof(ram_tab)); + + // Disable global interrupts + CRITICAL_SECTION_START; + + // Set the vector table base address to the SRAM copy + SCB->VTOR = (uint32_t)(&ram_tab); + + // Reenable interrupts + CRITICAL_SECTION_END; + + // Return the address of the table + return (pfnISR_Handler*)(&ram_tab); +} + +pfnISR_Handler install_isr(IRQn_Type irq, pfnISR_Handler newHandler) { + // Get the address of the relocated table + const pfnISR_Handler *isrtab = get_relocated_table_addr(); + + // Disable global interrupts + CRITICAL_SECTION_START; + + // Get the original handler + pfnISR_Handler oldHandler = isrtab[irq + 16]; + + // Install the new one + isrtab[irq + 16] = newHandler; + + // Reenable interrupts + CRITICAL_SECTION_END; + + // Return the original one + return oldHandler; +} + +#endif diff --git a/Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.h b/Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.h new file mode 100644 index 0000000000..efc63de25d --- /dev/null +++ b/Marlin/src/HAL/HAL_DUE/InterruptVectors_Due.h @@ -0,0 +1,52 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free 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. + * + * 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 . + * + */ + +/** + * InterruptVectors_Due.h + * + * Copyright (c) 2017 Eduardo José Tagle. All right reserved + * + * This module relocates the Interrupt vector table to SRAM, allowing new + * interrupt handlers to be added at runtime. This is required because the + * Arduino runtime steals interrupt handlers that Marlin MUST use to support + * extended functionality such as USB hosts and USB devices (MSD, MTP) and + * custom serial port handlers. Rather than modifying and/or recompiling the + * Arduino runtime, We just want to run as much as possible on Stock Arduino. + * + * Copyright (c) 2017 Eduardo José Tagle. All right reserved + */ + +#ifndef INTERRUPTVECTORS_DUE_H +#define INTERRUPTVECTORS_DUE_H + +#include "../../inc/MarlinConfig.h" + +#ifdef ARDUINO_ARCH_SAM + +// ISR handler type +typedef void (*pfnISR_Handler)(void); + +// Install a new interrupt vector handler for the given irq, returning the old one +pfnISR_Handler install_isr(IRQn_Type irq, pfnISR_Handler newHandler); + +#endif // ARDUINO_ARCH_SAM +#endif // INTERRUPTVECTORS_DUE_H