From 203f2923a172b3f6fbaa0d3ec234fcb778dbceaf Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 25 Oct 2017 02:35:43 -0500 Subject: [PATCH 1/4] Cleanup, apply standards to debug_frmwrk.c Although this is an external contribution, clean up anyway to stop seeing it in global searches for typical flaws. --- .../CMSIS/LPC1768/driver/debug_frmwrk.c | 452 ++++++++---------- 1 file changed, 208 insertions(+), 244 deletions(-) diff --git a/frameworks/CMSIS/LPC1768/driver/debug_frmwrk.c b/frameworks/CMSIS/LPC1768/driver/debug_frmwrk.c index 7d7bae4b8..62e9b0001 100644 --- a/frameworks/CMSIS/LPC1768/driver/debug_frmwrk.c +++ b/frameworks/CMSIS/LPC1768/driver/debug_frmwrk.c @@ -1,11 +1,11 @@ /********************************************************************** -* $Id$ debug_frmwrk.c 2010-05-21 -*//** -* @file debug_frmwrk.c -* @brief Contains some utilities that used for debugging through UART -* @version 2.0 -* @date 21. May. 2010 -* @author NXP MCU SW Application Team +* $Id$ debug_frmwrk.c 2010-05-21 +* +* @file debug_frmwrk.c +* @brief Contains some utilities that used for debugging through UART +* @version 2.0 +* @date 21. May. 2010 +* @author NXP MCU SW Application Team * * Copyright(C) 2010, NXP Semiconductor * All rights reserved. @@ -37,12 +37,13 @@ * otherwise the default FW library configuration file must be included instead */ #ifdef __BUILD_WITH_EXAMPLE__ -#include "lpc17xx_libcfg.h" + #include "lpc17xx_libcfg.h" #else -#include "lpc17xx_libcfg_default.h" -#endif /* __BUILD_WITH_EXAMPLE__ */ + #include "lpc17xx_libcfg_default.h" +#endif #ifdef _DBGFWK + /* Debug framework */ static Bool debug_frmwrk_initialized = FALSE; @@ -59,284 +60,247 @@ uint8_t (*_db_get_char)(LPC_UART_TypeDef *UARTx) = UARTGetChar; /*********************************************************************//** - * @brief Puts a character to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] ch Character to put - * @return None + * @brief Puts a character to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] ch Character to put + * @return None **********************************************************************/ -void UARTPutChar (LPC_UART_TypeDef *UARTx, uint8_t ch) -{ +void UARTPutChar(LPC_UART_TypeDef *UARTx, uint8_t ch) { if (debug_frmwrk_initialized) - UART_Send(UARTx, &ch, 1, BLOCKING); + UART_Send(UARTx, &ch, 1, BLOCKING); } - /*********************************************************************//** - * @brief Get a character to UART port - * @param[in] UARTx Pointer to UART peripheral - * @return character value that returned + * @brief Get a character to UART port + * @param[in] UARTx Pointer to UART peripheral + * @return character value that returned **********************************************************************/ -uint8_t UARTGetChar (LPC_UART_TypeDef *UARTx) -{ +uint8_t UARTGetChar(LPC_UART_TypeDef *UARTx) { uint8_t tmp = 0; - + if (debug_frmwrk_initialized) UART_Receive(UARTx, &tmp, 1, BLOCKING); - - return(tmp); -} - -/*********************************************************************//** - * @brief Puts a string to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] str string to put - * @return None - **********************************************************************/ -void UARTPuts(LPC_UART_TypeDef *UARTx, const void *str) -{ - uint8_t *s = (uint8_t *) str; - - if (!debug_frmwrk_initialized) - return; - - while (*s) - { - UARTPutChar(UARTx, *s++); - } -} - - -/*********************************************************************//** - * @brief Puts a string to UART port and print new line - * @param[in] UARTx Pointer to UART peripheral - * @param[in] str String to put - * @return None - **********************************************************************/ -void UARTPuts_(LPC_UART_TypeDef *UARTx, const void *str) -{ - if (!debug_frmwrk_initialized) - return; - - UARTPuts (UARTx, str); - UARTPuts (UARTx, "\n\r"); -} - - -/*********************************************************************//** - * @brief Puts a decimal number to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] decnum Decimal number (8-bit long) - * @return None - **********************************************************************/ -void UARTPutDec(LPC_UART_TypeDef *UARTx, uint8_t decnum) -{ - if (!debug_frmwrk_initialized) - return; - - uint8_t c1=decnum%10; - uint8_t c2=(decnum/10)%10; - uint8_t c3=(decnum/100)%10; - UARTPutChar(UARTx, '0'+c3); - UARTPutChar(UARTx, '0'+c2); - UARTPutChar(UARTx, '0'+c1); + return(tmp); } /*********************************************************************//** - * @brief Puts a decimal number to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] decnum Decimal number (8-bit long) - * @return None + * @brief Puts a string to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] str string to put + * @return None **********************************************************************/ -void UARTPutDec16(LPC_UART_TypeDef *UARTx, uint16_t decnum) -{ - if (!debug_frmwrk_initialized) - return; +void UARTPuts(LPC_UART_TypeDef *UARTx, const void *str) { + if (!debug_frmwrk_initialized) return; - uint8_t c1=decnum%10; - uint8_t c2=(decnum/10)%10; - uint8_t c3=(decnum/100)%10; - uint8_t c4=(decnum/1000)%10; - uint8_t c5=(decnum/10000)%10; - UARTPutChar(UARTx, '0'+c5); - UARTPutChar(UARTx, '0'+c4); - UARTPutChar(UARTx, '0'+c3); - UARTPutChar(UARTx, '0'+c2); - UARTPutChar(UARTx, '0'+c1); + uint8_t *s = (uint8_t*)str; + while (*s) UARTPutChar(UARTx, *s++); } /*********************************************************************//** - * @brief Puts a decimal number to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] decnum Decimal number (8-bit long) - * @return None + * @brief Puts a string to UART port and print new line + * @param[in] UARTx Pointer to UART peripheral + * @param[in] str String to put + * @return None **********************************************************************/ -void UARTPutDec32(LPC_UART_TypeDef *UARTx, uint32_t decnum) -{ - if (!debug_frmwrk_initialized) - return; +void UARTPuts_(LPC_UART_TypeDef *UARTx, const void *str) { + if (!debug_frmwrk_initialized) return; - uint8_t c1=decnum%10; - uint8_t c2=(decnum/10)%10; - uint8_t c3=(decnum/100)%10; - uint8_t c4=(decnum/1000)%10; - uint8_t c5=(decnum/10000)%10; - uint8_t c6=(decnum/100000)%10; - uint8_t c7=(decnum/1000000)%10; - uint8_t c8=(decnum/10000000)%10; - uint8_t c9=(decnum/100000000)%10; - uint8_t c10=(decnum/1000000000)%10; - UARTPutChar(UARTx, '0'+c10); - UARTPutChar(UARTx, '0'+c9); - UARTPutChar(UARTx, '0'+c8); - UARTPutChar(UARTx, '0'+c7); - UARTPutChar(UARTx, '0'+c6); - UARTPutChar(UARTx, '0'+c5); - UARTPutChar(UARTx, '0'+c4); - UARTPutChar(UARTx, '0'+c3); - UARTPutChar(UARTx, '0'+c2); - UARTPutChar(UARTx, '0'+c1); + UARTPuts (UARTx, str); + UARTPuts (UARTx, "\n\r"); } /*********************************************************************//** - * @brief Puts a hex number to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] hexnum Hex number (8-bit long) - * @return None + * @brief Puts a decimal number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] decnum Decimal number (8-bit long) + * @return None **********************************************************************/ -void UARTPutHex (LPC_UART_TypeDef *UARTx, uint8_t hexnum) -{ - uint8_t nibble, i; - - if (!debug_frmwrk_initialized) - return; +void UARTPutDec(LPC_UART_TypeDef *UARTx, uint8_t decnum) { + if (!debug_frmwrk_initialized) return; - UARTPuts(UARTx, "0x"); - i = 1; - do { - nibble = (hexnum >> (4*i)) & 0x0F; - UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); - } while (i--); -} - - -/*********************************************************************//** - * @brief Puts a hex number to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] hexnum Hex number (16-bit long) - * @return None - **********************************************************************/ -void UARTPutHex16 (LPC_UART_TypeDef *UARTx, uint16_t hexnum) -{ - uint8_t nibble, i; - - if (!debug_frmwrk_initialized) - return; - - UARTPuts(UARTx, "0x"); - i = 3; - do { - nibble = (hexnum >> (4*i)) & 0x0F; - UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); - } while (i--); + uint8_t c1 = decnum%10; + uint8_t c2 = (decnum / 10) % 10; + uint8_t c3 = (decnum / 100) % 10; + UARTPutChar(UARTx, '0'+c3); + UARTPutChar(UARTx, '0'+c2); + UARTPutChar(UARTx, '0'+c1); } /*********************************************************************//** - * @brief Puts a hex number to UART port - * @param[in] UARTx Pointer to UART peripheral - * @param[in] hexnum Hex number (32-bit long) - * @return None + * @brief Puts a decimal number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] decnum Decimal number (8-bit long) + * @return None **********************************************************************/ -void UARTPutHex32 (LPC_UART_TypeDef *UARTx, uint32_t hexnum) -{ - uint8_t nibble, i; - - if (!debug_frmwrk_initialized) - return; +void UARTPutDec16(LPC_UART_TypeDef *UARTx, uint16_t decnum) { + if (!debug_frmwrk_initialized) return; - UARTPuts(UARTx, "0x"); - i = 7; - do { - nibble = (hexnum >> (4*i)) & 0x0F; - UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); - } while (i--); + uint8_t c1 = decnum%10; + uint8_t c2 = (decnum / 10) % 10; + uint8_t c3 = (decnum / 100) % 10; + uint8_t c4 = (decnum / 1000) % 10; + uint8_t c5 = (decnum / 10000) % 10; + UARTPutChar(UARTx, '0'+c5); + UARTPutChar(UARTx, '0'+c4); + UARTPutChar(UARTx, '0'+c3); + UARTPutChar(UARTx, '0'+c2); + UARTPutChar(UARTx, '0'+c1); } -///*********************************************************************//** -// * @brief print function that supports format as same as printf() -// * function of library -// * @param[in] None -// * @return None -// **********************************************************************/ -//void _printf (const char *format, ...) -//{ -// static char buffer[512 + 1]; -// va_list vArgs; -// char *tmp; -// va_start(vArgs, format); -// vsprintf((char *)buffer, (char const *)format, vArgs); -// va_end(vArgs); +/*********************************************************************//** + * @brief Puts a decimal number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] decnum Decimal number (8-bit long) + * @return None + **********************************************************************/ +void UARTPutDec32(LPC_UART_TypeDef *UARTx, uint32_t decnum) { + if (!debug_frmwrk_initialized) return; + + const uint8_t c1 = decnum % 10, + c2 = (decnum / 10) % 10, + c3 = (decnum / 100) % 10, + c4 = (decnum / 1000) % 10, + c5 = (decnum / 10000) % 10, + c6 = (decnum / 100000) % 10, + c7 = (decnum / 1000000) % 10, + c8 = (decnum / 10000000) % 10, + c9 = (decnum / 100000000) % 10, + c10 = (decnum / 1000000000) % 10; + UARTPutChar(UARTx, '0' + c10); + UARTPutChar(UARTx, '0' + c9); + UARTPutChar(UARTx, '0' + c8); + UARTPutChar(UARTx, '0' + c7); + UARTPutChar(UARTx, '0' + c6); + UARTPutChar(UARTx, '0' + c5); + UARTPutChar(UARTx, '0' + c4); + UARTPutChar(UARTx, '0' + c3); + UARTPutChar(UARTx, '0' + c2); + UARTPutChar(UARTx, '0' + c1); +} + +/*********************************************************************//** + * @brief Puts a hex number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] hexnum Hex number (8-bit long) + * @return None + **********************************************************************/ +void UARTPutHex(LPC_UART_TypeDef *UARTx, uint8_t hexnum) { + if (!debug_frmwrk_initialized) return; + + UARTPuts(UARTx, "0x"); + uint8_t nibble, i = 1; + do { + nibble = (hexnum >> (4 * i)) & 0x0F; + UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); + } while (i--); +} + +/*********************************************************************//** + * @brief Puts a hex number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] hexnum Hex number (16-bit long) + * @return None + **********************************************************************/ +void UARTPutHex16(LPC_UART_TypeDef *UARTx, uint16_t hexnum) { + if (!debug_frmwrk_initialized) return; + + UARTPuts(UARTx, "0x"); + uint8_t nibble, i = 3; + do { + nibble = (hexnum >> (4 * i)) & 0x0F; + UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); + } while (i--); +} + +/*********************************************************************//** + * @brief Puts a hex number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] hexnum Hex number (32-bit long) + * @return None + **********************************************************************/ +void UARTPutHex32(LPC_UART_TypeDef *UARTx, uint32_t hexnum) { + if (!debug_frmwrk_initialized) return; + + UARTPuts(UARTx, "0x"); + uint8_t nibble, i = 7; + do { + nibble = (hexnum >> (4 * i)) & 0x0F; + UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); + } while (i--); +} + +/*********************************************************************//** + * @brief print function that supports format as same as printf() + * function of library + * @param[in] None + * @return None + **********************************************************************/ +//void _printf (const char *format, ...) { +// static char buffer[512 + 1]; +// va_list vArgs; +// char *tmp; +// va_start(vArgs, format); +// vsprintf((char *)buffer, (char const *)format, vArgs); +// va_end(vArgs); // -// _DBG(buffer); +// _DBG(buffer); //} /*********************************************************************//** - * @brief Initialize Debug frame work through initializing UART port - * @param[in] None - * @return None + * @brief Initialize Debug frame work through initializing UART port + * @param[in] None + * @return None **********************************************************************/ -void debug_frmwrk_init(void) -{ - UART_CFG_Type UARTConfigStruct; - PINSEL_CFG_Type PinCfg; +void debug_frmwrk_init(void) { + UART_CFG_Type UARTConfigStruct; + PINSEL_CFG_Type PinCfg; -#if (USED_UART_DEBUG_PORT==0) - /* - * Initialize UART0 pin connect - */ - PinCfg.Funcnum = 1; - PinCfg.OpenDrain = 0; - PinCfg.Pinmode = 0; - PinCfg.Pinnum = 2; - PinCfg.Portnum = 0; - PINSEL_ConfigPin(&PinCfg); - PinCfg.Pinnum = 3; - PINSEL_ConfigPin(&PinCfg); + #if (USED_UART_DEBUG_PORT==0) + /* + * Initialize UART0 pin connect + */ + PinCfg.Funcnum = 1; + PinCfg.OpenDrain = 0; + PinCfg.Pinmode = 0; + PinCfg.Pinnum = 2; + PinCfg.Portnum = 0; + PINSEL_ConfigPin(&PinCfg); + PinCfg.Pinnum = 3; + PINSEL_ConfigPin(&PinCfg); -#elif (USED_UART_DEBUG_PORT==1) - /* - * Initialize UART1 pin connect - */ - PinCfg.Funcnum = 1; - PinCfg.OpenDrain = 0; - PinCfg.Pinmode = 0; - PinCfg.Pinnum = 15; - PinCfg.Portnum = 0; - PINSEL_ConfigPin(&PinCfg); - PinCfg.Pinnum = 16; - PINSEL_ConfigPin(&PinCfg); -#endif + #elif (USED_UART_DEBUG_PORT==1) + /* + * Initialize UART1 pin connect + */ + PinCfg.Funcnum = 1; + PinCfg.OpenDrain = 0; + PinCfg.Pinmode = 0; + PinCfg.Pinnum = 15; + PinCfg.Portnum = 0; + PINSEL_ConfigPin(&PinCfg); + PinCfg.Pinnum = 16; + PINSEL_ConfigPin(&PinCfg); + #endif - /* Initialize UART Configuration parameter structure to default state: - * Baudrate = 9600bps - * 8 data bit - * 1 Stop bit - * None parity - */ - UART_ConfigStructInit(&UARTConfigStruct); + /* Initialize UART Configuration parameter structure to default state: + * Baudrate = 9600bps + * 8 data bit + * 1 Stop bit + * None parity + */ + UART_ConfigStructInit(&UARTConfigStruct); - // Re-configure baudrate to 115200bps - UARTConfigStruct.Baud_rate = 115200; + // Re-configure baudrate to 115200bps + UARTConfigStruct.Baud_rate = 115200; - // Initialize DEBUG_UART_PORT peripheral with given to corresponding parameter - UART_Init((LPC_UART_TypeDef *)DEBUG_UART_PORT, &UARTConfigStruct); + // Initialize DEBUG_UART_PORT peripheral with given to corresponding parameter + UART_Init((LPC_UART_TypeDef *)DEBUG_UART_PORT, &UARTConfigStruct); - // Enable UART Transmit - UART_TxCmd((LPC_UART_TypeDef *)DEBUG_UART_PORT, ENABLE); + // Enable UART Transmit + UART_TxCmd((LPC_UART_TypeDef *)DEBUG_UART_PORT, ENABLE); debug_frmwrk_initialized = TRUE; } -#endif /*_DBGFWK */ - -/* --------------------------------- End Of File ------------------------------ */ +#endif // _DBGFWK From c9bbef63805462d0d251d4453d2bf2bb0d7377c7 Mon Sep 17 00:00:00 2001 From: etagle Date: Wed, 11 Oct 2017 03:28:52 -0300 Subject: [PATCH 2/4] Cosmetic fix for HAL_AVR/MarlinSerial.cpp Instead of using const char, it is better to use uint8_t --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index 88258e119..025254481 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -84,7 +84,7 @@ // Currently looking for: M108, M112, M410 // If you alter the parser please don't forget to update the capabilities in Conditionals_post.h - FORCE_INLINE void emergency_parser(const unsigned char c) { + FORCE_INLINE void emergency_parser(const uint8_t c) { static e_parser_state state = state_RESET; @@ -169,13 +169,16 @@ #endif // EMERGENCY_PARSER FORCE_INLINE void store_rxd_char() { + const ring_buffer_pos_t h = rx_buffer.head, i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + // Read the character + const uint8_t c = M_UDRx; + // If the character is to be stored at the index just before the tail // (such that the head would advance to the current tail), the buffer is // critical, so don't write the character or advance the head. - const char c = M_UDRx; if (i != rx_buffer.tail) { rx_buffer.buffer[h] = c; rx_buffer.head = i; @@ -194,6 +197,7 @@ #endif #if ENABLED(SERIAL_XON_XOFF) + // for high speed transfers, we can use XON/XOFF protocol to do // software handshake and avoid overruns. if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { From 8d9c3cc2b74f5b8a3f765d2d6e901ee6c0abc987 Mon Sep 17 00:00:00 2001 From: etagle Date: Wed, 11 Oct 2017 03:33:19 -0300 Subject: [PATCH 3/4] 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 000000000..0a4677611 --- /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 000000000..efc63de25 --- /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 From ba8dc678f541295133653412c2874393f1e92c32 Mon Sep 17 00:00:00 2001 From: etagle Date: Wed, 11 Oct 2017 03:38:12 -0300 Subject: [PATCH 4/4] Arduino Due XON/XOFF implementation Alos includes emergency parser and configurable TX/RX buffers for Arduino Due. --- Marlin/src/HAL/HAL_DUE/HAL_Due.h | 75 +-- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 680 ++++++++++++++++++++ Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h | 142 ++++ Marlin/src/core/serial.h | 39 +- 4 files changed, 874 insertions(+), 62 deletions(-) create mode 100644 Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp create mode 100644 Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h diff --git a/Marlin/src/HAL/HAL_DUE/HAL_Due.h b/Marlin/src/HAL/HAL_DUE/HAL_Due.h index e1a9094d7..0aa7ab437 100644 --- a/Marlin/src/HAL/HAL_DUE/HAL_Due.h +++ b/Marlin/src/HAL/HAL_DUE/HAL_Due.h @@ -29,37 +29,35 @@ #ifndef _HAL_DUE_H #define _HAL_DUE_H -// -------------------------------------------------------------------------- -// Includes -// -------------------------------------------------------------------------- - #include #include "Arduino.h" #include "fastio_Due.h" #include "watchdog_Due.h" - #include "HAL_timers_Due.h" -// -------------------------------------------------------------------------- +// // Defines -// -------------------------------------------------------------------------- +// #if SERIAL_PORT == -1 #define MYSERIAL SerialUSB #elif SERIAL_PORT == 0 - #define MYSERIAL Serial + #define MYSERIAL customizedSerial #elif SERIAL_PORT == 1 - #define MYSERIAL Serial1 + #define MYSERIAL customizedSerial #elif SERIAL_PORT == 2 - #define MYSERIAL Serial2 + #define MYSERIAL customizedSerial #elif SERIAL_PORT == 3 - #define MYSERIAL Serial3 + #define MYSERIAL customizedSerial #endif #define _BV(bit) (1 << (bit)) +// We need the previous define before the include, or compilation bombs... +#include "MarlinSerial_Due.h" + #ifndef analogInputToDigitalPin #define analogInputToDigitalPin(p) ((p < 12u) ? (p) + 54u : -1) #endif @@ -102,46 +100,43 @@ typedef int8_t pin_t; // Public Variables // -------------------------------------------------------------------------- -/** result of last ADC conversion */ -extern uint16_t HAL_adc_result; +extern uint16_t HAL_adc_result; // result of last ADC conversion -// -------------------------------------------------------------------------- -// Public functions -// -------------------------------------------------------------------------- +void cli(void); // Disable interrupts +void sei(void); // Enable interrupts -// Disable interrupts -void cli(void); - -// Enable interrupts -void sei(void); - -/** clear reset reason */ -void HAL_clear_reset_source (void); - -/** reset reason */ -uint8_t HAL_get_reset_source (void); +void HAL_clear_reset_source(void); // clear reset reason +uint8_t HAL_get_reset_source(void); // get reset reason void _delay_ms(const int delay); int freeMemory(void); -// SPI: Extended functions which take a channel number (hardware SPI only) -/** Write single byte to specified SPI channel */ +/** + * SPI: Extended functions taking a channel number (hardware SPI only) + */ + +// Write single byte to specified SPI channel void spiSend(uint32_t chan, byte b); -/** Write buffer to specified SPI channel */ + +// Write buffer to specified SPI channel void spiSend(uint32_t chan, const uint8_t* buf, size_t n); -/** Read single byte from specified SPI channel */ + +// Read single byte from specified SPI channel uint8_t spiRec(uint32_t chan); +/** + * EEPROM + */ -// EEPROM void eeprom_write_byte(unsigned char *pos, unsigned char value); unsigned char eeprom_read_byte(unsigned char *pos); void eeprom_read_block (void *__dst, const void *__src, size_t __n); void eeprom_update_block (const void *__src, void *__dst, size_t __n); - -// ADC +/** + * ADC + */ #define HAL_ANALOG_SELECT(pin) @@ -150,20 +145,13 @@ inline void HAL_adc_init(void) {}//todo #define HAL_START_ADC(pin) HAL_adc_start_conversion(pin) #define HAL_READ_ADC HAL_adc_result - void HAL_adc_start_conversion(const uint8_t adc_pin); - uint16_t HAL_adc_get_result(void); - -// uint16_t HAL_getAdcReading(uint8_t chan); - void HAL_startAdcConversion(uint8_t chan); uint8_t HAL_pinToAdcChannel(int pin); - uint16_t HAL_getAdcFreerun(uint8_t chan, bool wait_for_conversion = false); //uint16_t HAL_getAdcSuperSample(uint8_t chan); - void HAL_enable_AdcFreerun(void); //void HAL_disable_AdcFreerun(uint8_t chan); @@ -171,9 +159,4 @@ void HAL_enable_AdcFreerun(void); #define GET_PIN_MAP_INDEX(pin) pin #define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval) -// -------------------------------------------------------------------------- -// -// -------------------------------------------------------------------------- - #endif // _HAL_DUE_H - diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp new file mode 100644 index 000000000..0acfb9942 --- /dev/null +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -0,0 +1,680 @@ +/** + * 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 . + * + */ + +/** + * MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE + * Copyright (c) 2017 Eduardo José Tagle. All right reserved + * Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved. + */ +#ifdef ARDUINO_ARCH_SAM + +#include "../../inc/MarlinConfig.h" + +#include "MarlinSerial_Due.h" +#include "InterruptVectors_Due.h" +#include "../../Marlin.h" + +// Based on selected port, use the proper configuration +#if SERIAL_PORT == 0 + #define HWUART UART + #define HWUART_IRQ UART_IRQn + #define HWUART_IRQ_ID ID_UART +#elif SERIAL_PORT == 1 + #define HWUART USART0 + #define HWUART_IRQ USART0_IRQn + #define HWUART_IRQ_ID ID_USART0 +#elif SERIAL_PORT == 2 + #define HWUART USART1 + #define HWUART_IRQ USART1_IRQn + #define HWUART_IRQ_ID ID_USART1 +#elif SERIAL_PORT == 3 + #define HWUART USART3 + #define HWUART_IRQ USART3_IRQn + #define HWUART_IRQ_ID ID_USART3 +#endif + +struct ring_buffer_r { + unsigned char buffer[RX_BUFFER_SIZE]; + volatile ring_buffer_pos_t head, tail; +}; + +#if TX_BUFFER_SIZE > 0 + struct ring_buffer_t { + unsigned char buffer[TX_BUFFER_SIZE]; + volatile uint8_t head, tail; + }; +#endif + +ring_buffer_r rx_buffer = { { 0 }, 0, 0 }; +#if TX_BUFFER_SIZE > 0 + ring_buffer_t tx_buffer = { { 0 }, 0, 0 }; + static bool _written; +#endif + +#if ENABLED(SERIAL_XON_XOFF) + constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80; // XON / XOFF Character was sent + constexpr uint8_t XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send + // XON / XOFF character definitions + constexpr uint8_t XON_CHAR = 17; + constexpr uint8_t XOFF_CHAR = 19; + uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR; + + // Validate that RX buffer size is at least 4096 bytes- According to several experiments, on + // the original Arduino Due that uses a ATmega16U2 as USB to serial bridge, due to the introduced + // latencies, at least 2959 bytes of RX buffering (when transmitting at 250kbits/s) are required + // to avoid overflows. + + #if RX_BUFFER_SIZE < 4096 + #error Arduino DUE requires at least 4096 bytes of RX buffer to avoid buffer overflows when using XON/XOFF handshake + #endif +#endif + +#if ENABLED(SERIAL_STATS_DROPPED_RX) + uint8_t rx_dropped_bytes = 0; +#endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + ring_buffer_pos_t rx_max_enqueued = 0; +#endif + +// A SW memory barrier, to ensure GCC does not overoptimize loops +#define sw_barrier() asm volatile("": : :"memory"); + +#if ENABLED(EMERGENCY_PARSER) + + #include "../../module/stepper.h" + + // Currently looking for: M108, M112, M410 + // If you alter the parser please don't forget to update the capabilities in Conditionals_post.h + + FORCE_INLINE void emergency_parser(const uint8_t c) { + + static e_parser_state state = state_RESET; + + switch (state) { + case state_RESET: + switch (c) { + case ' ': break; + case 'N': state = state_N; break; + case 'M': state = state_M; break; + default: state = state_IGNORE; + } + break; + + case state_N: + switch (c) { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': case '-': case ' ': break; + case 'M': state = state_M; break; + default: state = state_IGNORE; + } + break; + + case state_M: + switch (c) { + case ' ': break; + case '1': state = state_M1; break; + case '4': state = state_M4; break; + default: state = state_IGNORE; + } + break; + + case state_M1: + switch (c) { + case '0': state = state_M10; break; + case '1': state = state_M11; break; + default: state = state_IGNORE; + } + break; + + case state_M10: + state = (c == '8') ? state_M108 : state_IGNORE; + break; + + case state_M11: + state = (c == '2') ? state_M112 : state_IGNORE; + break; + + case state_M4: + state = (c == '1') ? state_M41 : state_IGNORE; + break; + + case state_M41: + state = (c == '0') ? state_M410 : state_IGNORE; + break; + + case state_IGNORE: + if (c == '\n') state = state_RESET; + break; + + default: + if (c == '\n') { + switch (state) { + case state_M108: + wait_for_user = wait_for_heatup = false; + break; + case state_M112: + kill(PSTR(MSG_KILLED)); + break; + case state_M410: + quickstop_stepper(); + break; + default: + break; + } + state = state_RESET; + } + } + } + +#endif // EMERGENCY_PARSER + +FORCE_INLINE void store_rxd_char() { + + const ring_buffer_pos_t h = rx_buffer.head, + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + + // Read the character + const uint8_t c = HWUART->UART_RHR; + + // If the character is to be stored at the index just before the tail + // (such that the head would advance to the current tail), the buffer is + // critical, so don't write the character or advance the head. + if (i != rx_buffer.tail) { + rx_buffer.buffer[h] = c; + rx_buffer.head = i; + } + #if ENABLED(SERIAL_STATS_DROPPED_RX) + else if (!++rx_dropped_bytes) ++rx_dropped_bytes; + #endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + // calculate count of bytes stored into the RX buffer + ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + // Keep track of the maximum count of enqueued bytes + NOLESS(rx_max_enqueued, rx_count); +#endif + +#if ENABLED(SERIAL_XON_XOFF) + + // for high speed transfers, we can use XON/XOFF protocol to do + // software handshake and avoid overruns. + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { + + // calculate count of bytes stored into the RX buffer + ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + + // if we are above 12.5% of RX buffer capacity, send XOFF before + // we run out of RX buffer space .. We need 325 bytes @ 250kbits/s to + // let the host react and stop sending bytes. This translates to 13mS + // propagation time. + if (rx_count >= (RX_BUFFER_SIZE) / 8) { + // If TX interrupts are disabled and data register is empty, + // just write the byte to the data register and be done. This + // shortcut helps significantly improve the effective datarate + // at high (>500kbit/s) bitrates, where interrupt overhead + // becomes a slowdown. + if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) { + // Send an XOFF character + HWUART->UART_THR = XOFF_CHAR; + + // And remember it was sent + xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; + } + else { + // TX interrupts disabled, but buffer still not empty ... or + // TX interrupts enabled. Reenable TX ints and schedule XOFF + // character to be sent + #if TX_BUFFER_SIZE > 0 + HWUART->UART_IER = UART_IER_TXRDY; + xon_xoff_state = XOFF_CHAR; + #else + // We are not using TX interrupts, we will have to send this manually + while (!(HWUART->UART_SR & UART_SR_TXRDY)) { sw_barrier(); }; + HWUART->UART_THR = XOFF_CHAR; + // And remember we already sent it + xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; + #endif + } + } + } +#endif // SERIAL_XON_XOFF + +#if ENABLED(EMERGENCY_PARSER) + emergency_parser(c); +#endif +} + +#if TX_BUFFER_SIZE > 0 + + FORCE_INLINE void _tx_thr_empty_irq(void) { + // If interrupts are enabled, there must be more data in the output + // buffer. + + #if ENABLED(SERIAL_XON_XOFF) + // Do a priority insertion of an XON/XOFF char, if needed. + const uint8_t state = xon_xoff_state; + if (!(state & XON_XOFF_CHAR_SENT)) { + HWUART->UART_THR = state & XON_XOFF_CHAR_MASK; + xon_xoff_state = state | XON_XOFF_CHAR_SENT; + } + else + #endif + { // Send the next byte + const uint8_t t = tx_buffer.tail, c = tx_buffer.buffer[t]; + tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1); + HWUART->UART_THR = c; + } + + // Disable interrupts if the buffer is empty + if (tx_buffer.head == tx_buffer.tail) + HWUART->UART_IDR = UART_IDR_TXRDY; + } + +#endif // TX_BUFFER_SIZE + +static void UART_ISR(void) { + uint32_t status = HWUART->UART_SR; + + // Did we receive data? + if (status & UART_SR_RXRDY) + store_rxd_char(); + + #if TX_BUFFER_SIZE > 0 + // Do we have something to send, and TX interrupts are enabled (meaning something to send) ? + if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) + _tx_thr_empty_irq(); + #endif + + // Acknowledge errors + if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) { + // TODO: error reporting outside ISR + HWUART->UART_CR = UART_CR_RSTSTA; + } +} + +// Public Methods + +void MarlinSerial::begin(const long baud_setting) { + + // Disable UART interrupt in NVIC + NVIC_DisableIRQ( HWUART_IRQ ); + + // Disable clock + pmc_disable_periph_clk( HWUART_IRQ_ID ); + + // Configure PMC + pmc_enable_periph_clk( HWUART_IRQ_ID ); + + // Disable PDC channel + HWUART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; + + // Reset and disable receiver and transmitter + HWUART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; + + // Configure mode: 8bit, No parity, 1 bit stop + HWUART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO; + + // Configure baudrate (asynchronous, no oversampling) + HWUART->UART_BRGR = (SystemCoreClock / (baud_setting << 4)); + + // Configure interrupts + HWUART->UART_IDR = 0xFFFFFFFF; + HWUART->UART_IER = UART_IER_RXRDY | UART_IER_OVRE | UART_IER_FRAME; + + // Install interrupt handler + install_isr(HWUART_IRQ, UART_ISR); + + // Enable UART interrupt in NVIC + NVIC_EnableIRQ(HWUART_IRQ); + + // Enable receiver and transmitter + HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN; + + #if TX_BUFFER_SIZE > 0 + _written = false; + #endif +} + +void MarlinSerial::end() { + // Disable UART interrupt in NVIC + NVIC_DisableIRQ( HWUART_IRQ ); + + pmc_disable_periph_clk( HWUART_IRQ_ID ); +} + +void MarlinSerial::checkRx(void) { + if (HWUART->UART_SR & UART_SR_RXRDY) { + CRITICAL_SECTION_START; + store_rxd_char(); + CRITICAL_SECTION_END; + } +} + +int MarlinSerial::peek(void) { + CRITICAL_SECTION_START; + const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail]; + CRITICAL_SECTION_END; + return v; +} + +int MarlinSerial::read(void) { + int v; + CRITICAL_SECTION_START; + const ring_buffer_pos_t t = rx_buffer.tail; + if (rx_buffer.head == t) + v = -1; + else { + v = rx_buffer.buffer[t]; + rx_buffer.tail = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1); + + #if ENABLED(SERIAL_XON_XOFF) + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { + // Get count of bytes in the RX buffer + ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + // When below 10% of RX buffer capacity, send XON before + // running out of RX buffer bytes + if (rx_count < (RX_BUFFER_SIZE) / 10) { + xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; + CRITICAL_SECTION_END; // End critical section before returning! + writeNoHandshake(XON_CHAR); + return v; + } + } + #endif + } + CRITICAL_SECTION_END; + return v; +} + +ring_buffer_pos_t MarlinSerial::available(void) { + CRITICAL_SECTION_START; + const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail; + CRITICAL_SECTION_END; + return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1); +} + +void MarlinSerial::flush(void) { + // Don't change this order of operations. If the RX interrupt occurs between + // reading rx_buffer_head and updating rx_buffer_tail, the previous rx_buffer_head + // may be written to rx_buffer_tail, making the buffer appear full rather than empty. + CRITICAL_SECTION_START; + rx_buffer.head = rx_buffer.tail; + CRITICAL_SECTION_END; + +#if ENABLED(SERIAL_XON_XOFF) + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { + xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; + writeNoHandshake(XON_CHAR); + } +#endif +} + +#if TX_BUFFER_SIZE > 0 + uint8_t MarlinSerial::availableForWrite(void) { + CRITICAL_SECTION_START; + const uint8_t h = tx_buffer.head, t = tx_buffer.tail; + CRITICAL_SECTION_END; + return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1); + } + + void MarlinSerial::write(const uint8_t c) { + #if ENABLED(SERIAL_XON_XOFF) + const uint8_t state = xon_xoff_state; + if (!(state & XON_XOFF_CHAR_SENT)) { + // Send 2 chars: XON/XOFF, then a user-specified char + writeNoHandshake(state & XON_XOFF_CHAR_MASK); + xon_xoff_state = state | XON_XOFF_CHAR_SENT; + } + #endif + writeNoHandshake(c); + } + + void MarlinSerial::writeNoHandshake(const uint8_t c) { + _written = true; + CRITICAL_SECTION_START; + bool emty = (tx_buffer.head == tx_buffer.tail); + CRITICAL_SECTION_END; + // If the buffer and the data register is empty, just write the byte + // to the data register and be done. This shortcut helps + // significantly improve the effective datarate at high (> + // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. + if (emty && (HWUART->UART_SR & UART_SR_TXRDY)) { + CRITICAL_SECTION_START; + HWUART->UART_THR = c; + HWUART->UART_IER = UART_IER_TXRDY; + CRITICAL_SECTION_END; + return; + } + const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1); + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == tx_buffer.tail) { + if (__get_PRIMASK()) { + // Interrupts are disabled, so we'll have to poll the data + // register empty flag ourselves. If it is set, pretend an + // interrupt has happened and call the handler to free up + // space for us. + if (HWUART->UART_SR & UART_SR_TXRDY) + _tx_thr_empty_irq(); + } + else { + // nop, the interrupt handler will free up space for us + } + sw_barrier(); + } + + tx_buffer.buffer[tx_buffer.head] = c; + { CRITICAL_SECTION_START; + tx_buffer.head = i; + HWUART->UART_IER = UART_IER_TXRDY; + CRITICAL_SECTION_END; + } + return; + } + + void MarlinSerial::flushTX(void) { + // TX + // If we have never written a byte, no need to flush. + if (!_written) + return; + + while ((HWUART->UART_IMR & UART_IMR_TXRDY) || !(HWUART->UART_SR & UART_SR_TXEMPTY)) { + if (__get_PRIMASK()) + if ((HWUART->UART_SR & UART_SR_TXRDY)) + _tx_thr_empty_irq(); + sw_barrier(); + } + // If we get here, nothing is queued anymore (TX interrupts are disabled) and + // the hardware finished tranmission (TXEMPTY is set). + } + +#else // TX_BUFFER_SIZE == 0 + + void MarlinSerial::write(const uint8_t c) { + #if ENABLED(SERIAL_XON_XOFF) + // Do a priority insertion of an XON/XOFF char, if needed. + const uint8_t state = xon_xoff_state; + if (!(state & XON_XOFF_CHAR_SENT)) { + writeNoHandshake(state & XON_XOFF_CHAR_MASK); + xon_xoff_state = state | XON_XOFF_CHAR_SENT; + } + #endif + writeNoHandshake(c); + } + + void MarlinSerial::writeNoHandshake(const uint8_t c) { + while (!(HWUART->UART_SR & UART_SR_TXRDY)) { sw_barrier(); }; + HWUART->UART_THR = c; + } + +#endif // TX_BUFFER_SIZE == 0 + +/** +* Imports from print.h +*/ + +void MarlinSerial::print(char c, int base) { + print((long)c, base); +} + +void MarlinSerial::print(unsigned char b, int base) { + print((unsigned long)b, base); +} + +void MarlinSerial::print(int n, int base) { + print((long)n, base); +} + +void MarlinSerial::print(unsigned int n, int base) { + print((unsigned long)n, base); +} + +void MarlinSerial::print(long n, int base) { + if (base == 0) + write(n); + else if (base == 10) { + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); + } + else + printNumber(n, base); +} + +void MarlinSerial::print(unsigned long n, int base) { + if (base == 0) write(n); + else printNumber(n, base); +} + +void MarlinSerial::print(double n, int digits) { + printFloat(n, digits); +} + +void MarlinSerial::println(void) { + print('\r'); + print('\n'); +} + +void MarlinSerial::println(const String& s) { + print(s); + println(); +} + +void MarlinSerial::println(const char c[]) { + print(c); + println(); +} + +void MarlinSerial::println(char c, int base) { + print(c, base); + println(); +} + +void MarlinSerial::println(unsigned char b, int base) { + print(b, base); + println(); +} + +void MarlinSerial::println(int n, int base) { + print(n, base); + println(); +} + +void MarlinSerial::println(unsigned int n, int base) { + print(n, base); + println(); +} + +void MarlinSerial::println(long n, int base) { + print(n, base); + println(); +} + +void MarlinSerial::println(unsigned long n, int base) { + print(n, base); + println(); +} + +void MarlinSerial::println(double n, int digits) { + print(n, digits); + println(); +} + +// Private Methods + +void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + if (n) { + unsigned char buf[8 * sizeof(long)]; // Enough space for base 2 + int8_t i = 0; + while (n) { + buf[i++] = n % base; + n /= base; + } + while (i--) + print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10))); + } + else + print('0'); +} + +void MarlinSerial::printFloat(double number, uint8_t digits) { + // Handle negative numbers + if (number < 0.0) { + print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i = 0; i < digits; ++i) + rounding *= 0.1; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + print(int_part); + + // Print the decimal point, but only if there are digits beyond + if (digits) { + print('.'); + // Extract digits from the remainder one at a time + while (digits--) { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; + } + } +} + +// Preinstantiate +MarlinSerial customizedSerial; + +#endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h new file mode 100644 index 000000000..740db4d9c --- /dev/null +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h @@ -0,0 +1,142 @@ +/** + * 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 . + * + */ + +/** + * MarlinSerial_Due.h - Hardware serial library for Arduino DUE + * Copyright (c) 2017 Eduardo José Tagle. All right reserved + * Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved. + */ + +#ifndef MARLINSERIAL_DUE_H +#define MARLINSERIAL_DUE_H + +#include "../../inc/MarlinConfig.h" + +#include + +#ifndef SERIAL_PORT + #define SERIAL_PORT 0 +#endif + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 +#define BYTE 0 + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which rx_buffer_head is the index of the +// location to which to write the next incoming character and rx_buffer_tail +// is the index of the location from which to read. +// 256 is the max limit due to uint8_t head and tail. Use only powers of 2. (...,16,32,64,128,256) +#ifndef RX_BUFFER_SIZE + #define RX_BUFFER_SIZE 128 +#endif +#ifndef TX_BUFFER_SIZE + #define TX_BUFFER_SIZE 32 +#endif + +#if ENABLED(SERIAL_XON_XOFF) && RX_BUFFER_SIZE < 1024 + #error "XON/XOFF requires RX_BUFFER_SIZE >= 1024 for reliable transfers without drops." +#endif + +#if !IS_POWER_OF_2(RX_BUFFER_SIZE) || RX_BUFFER_SIZE < 2 + #error "RX_BUFFER_SIZE must be a power of 2 greater than 1." +#endif + +#if TX_BUFFER_SIZE && (TX_BUFFER_SIZE < 2 || TX_BUFFER_SIZE > 256 || !IS_POWER_OF_2(TX_BUFFER_SIZE)) + #error "TX_BUFFER_SIZE must be 0 or a power of 2 greater than 1." +#endif + +#if RX_BUFFER_SIZE > 256 + typedef uint16_t ring_buffer_pos_t; +#else + typedef uint8_t ring_buffer_pos_t; +#endif + +#if ENABLED(SERIAL_STATS_DROPPED_RX) + extern uint8_t rx_dropped_bytes; +#endif + +#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + extern ring_buffer_pos_t rx_max_enqueued; +#endif + +class MarlinSerial { + +public: + MarlinSerial() {}; + static void begin(const long); + static void end(); + static int peek(void); + static int read(void); + static void flush(void); + static ring_buffer_pos_t available(void); + static void checkRx(void); + static void write(const uint8_t c); + #if TX_BUFFER_SIZE > 0 + static uint8_t availableForWrite(void); + static void flushTX(void); + #endif + static void writeNoHandshake(const uint8_t c); + + #if ENABLED(SERIAL_STATS_DROPPED_RX) + FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; } + #endif + + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; } + #endif + + static FORCE_INLINE void write(const char* str) { while (*str) write(*str++); } + static FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); } + static FORCE_INLINE void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); } + static FORCE_INLINE void print(const char* str) { write(str); } + + static void print(char, int = BYTE); + static void print(unsigned char, int = BYTE); + static void print(int, int = DEC); + static void print(unsigned int, int = DEC); + static void print(long, int = DEC); + static void print(unsigned long, int = DEC); + static void print(double, int = 2); + + static void println(const String& s); + static void println(const char[]); + static void println(char, int = BYTE); + static void println(unsigned char, int = BYTE); + static void println(int, int = DEC); + static void println(unsigned int, int = DEC); + static void println(long, int = DEC); + static void println(unsigned long, int = DEC); + static void println(double, int = 2); + static void println(void); + operator bool() { return true; } + +private: + static void printNumber(unsigned long, const uint8_t); + static void printFloat(double, uint8_t); +}; + +extern MarlinSerial customizedSerial; + +#endif // MARLINSERIAL_DUE_H diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index 07d3ac173..887402a06 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -25,6 +25,25 @@ #include "../inc/MarlinConfig.h" +#if HAS_ABL && ENABLED(DEBUG_LEVELING_FEATURE) + #include "../libs/vector_3.h" +#endif + +/** + * Define debug bit-masks + */ +enum DebugFlags { + DEBUG_NONE = 0, + DEBUG_ECHO = _BV(0), ///< Echo commands in order as they are processed + DEBUG_INFO = _BV(1), ///< Print messages for code that has debug output + DEBUG_ERRORS = _BV(2), ///< Not implemented + DEBUG_DRYRUN = _BV(3), ///< Ignore temperature setting and E movement commands + DEBUG_COMMUNICATION = _BV(4), ///< Not implemented + DEBUG_LEVELING = _BV(5), ///< Print detailed output for homing and leveling + DEBUG_MESH_ADJUST = _BV(6), ///< UBL bed leveling + DEBUG_ALL = 0xFF +}; + //todo: HAL: breaks encapsulation // For AVR only, define a serial interface based on configuration #ifdef __AVR__ @@ -41,22 +60,10 @@ #endif #endif -#include "../libs/vector_3.h" - -/** - * Define debug bit-masks - */ -enum DebugFlags { - DEBUG_NONE = 0, - DEBUG_ECHO = _BV(0), ///< Echo commands in order as they are processed - DEBUG_INFO = _BV(1), ///< Print messages for code that has debug output - DEBUG_ERRORS = _BV(2), ///< Not implemented - DEBUG_DRYRUN = _BV(3), ///< Ignore temperature setting and E movement commands - DEBUG_COMMUNICATION = _BV(4), ///< Not implemented - DEBUG_LEVELING = _BV(5), ///< Print detailed output for homing and leveling - DEBUG_MESH_ADJUST = _BV(6), ///< UBL bed leveling - DEBUG_ALL = 0xFF -}; +#ifdef ARDUINO_ARCH_SAM + // To pull the Serial port definitions and overrides + #include "../HAL/HAL_DUE/MarlinSerial_Due.h" +#endif extern uint8_t marlin_debug_flags; #define DEBUGGING(F) (marlin_debug_flags & (DEBUG_## F))