Bump to head with specific board definition, implement fan as laser

This commit is contained in:
InsanityAutomation
2018-09-28 12:08:23 -04:00
parent 5400f6ecf8
commit be805a8132
427 changed files with 49634 additions and 10430 deletions
+7 -3
View File
@@ -51,7 +51,7 @@ jobs:
export PATH=`pwd`/buildroot/bin/:${PATH}
# Generate custom version include
generate_version_header_for_marlin ./Marlin/src/inc
generate_version ./Marlin/src/inc
cat ./Marlin/src/inc/_Version.h
#
# Backup pins_RAMPS.h
@@ -59,6 +59,8 @@ jobs:
cp Marlin/src/pins/pins_RAMPS.h Marlin/src/pins/pins_RAMPS.h.backup
#
env_backup
#################################
# Build all sample configurations
#################################
@@ -279,11 +281,13 @@ jobs:
# Remove temp files from dependencies tree prior to caching
rm -rf ~/Marlin/.piolibdeps/_tmp_*
#
# Restore the environment
#
env_restore
- save_cache:
paths:
- ~/.platformio
- ~/Marlin/.piolibdeps
key: v1-dependencies-{{ checksum "~/Marlin/platformio.ini" }}
+1 -1
View File
@@ -45,7 +45,7 @@ before_script:
- cd ${TRAVIS_BUILD_DIR}
#
# Generate custom version include
- generate_version_header_for_marlin ${TRAVIS_BUILD_DIR}/Marlin/src/inc
- generate_version ${TRAVIS_BUILD_DIR}/Marlin/src/inc
- cat ${TRAVIS_BUILD_DIR}/Marlin/src/inc/_Version.h
#
script:
+1 -1
View File
@@ -145,7 +145,7 @@
// The following define selects which electronics board you have.
// Please choose the name from boards.h that matches your setup
#ifndef MOTHERBOARD
#define MOTHERBOARD BOARD_RUMBA
#define MOTHERBOARD BOARD_FORMBOT_TREX2PLUS
#endif
// Optional custom name for your RepStrap or other custom machine
+4 -1
View File
@@ -748,6 +748,9 @@
#define DOUBLECLICK_MAX_INTERVAL 1250 // Maximum interval between clicks, in milliseconds.
// Note: Extra time may be added to mitigate controller latency.
#define BABYSTEP_ZPROBE_GFX_OVERLAY // Enable graphical overlay on Z-offset editor
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
#define BABYSTEP_HOTEND_Z_OFFSET // For multiple hotends, babystep relative Z offsets
#endif
#endif
// @section extruder
@@ -1556,7 +1559,7 @@
#define USER_DESC_1 "UBL Commission Step 1"
#define USER_GCODE_1 "M502 \n M500 \n M501 \n T0 \n M190 S75 \n M106 S128 \n M104 S225 \n G28 \n G29 P1 \n G29 S1 \n M117 Run Step 2 \n"
#define USER_DESC_2 "UBL Commission Step 2"
#define USER_GCODE_2 "G29 S1 \n G29 S0 \n G29 F 10.0 \n G29 A \n M500 \n G28 \n G29 L1 \n T0 \n M106 S128 \n M109 S225 \n G1 X150 Y 150 \n G1 Z0 \n M117 Set Z Offset \n"
+2 -3
View File
@@ -574,9 +574,8 @@ CSTANDARD = -std=gnu99
CXXSTANDARD = -std=gnu++11
CDEBUG = -g$(DEBUG)
CWARN = -Wall -Wstrict-prototypes
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct \
-fshort-enums -w -ffunction-sections -fdata-sections \
-flto \
CTUNING = -w -fsigned-char -funsigned-bitfields -fpack-struct \
-fshort-enums -ffunction-sections -fdata-sections -flto \
-DARDUINO=$(ARDUINO_VERSION)
ifneq ($(HARDWARE_MOTHERBOARD),)
CTUNING += -DMOTHERBOARD=${HARDWARE_MOTHERBOARD}
+5 -3
View File
@@ -34,7 +34,7 @@
#include <avr/interrupt.h>
#include <avr/io.h>
#include "../HAL_SPI.h"
#include "../shared/HAL_SPI.h"
#include "fastio_AVR.h"
#include "watchdog_AVR.h"
#include "math_AVR.h"
@@ -170,8 +170,6 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t freque
#define _CAT(a, ...) a ## __VA_ARGS__
#define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare)
#define HAL_timer_restrain(timer, interval_ticks) NOLESS(_CAT(TIMER_OCR_, timer), _CAT(TIMER_COUNTER_, timer) + interval_ticks)
#define HAL_timer_get_compare(timer) _CAT(TIMER_OCR_, timer)
#define HAL_timer_get_count(timer) _CAT(TIMER_COUNTER_, timer)
@@ -354,6 +352,10 @@ inline void HAL_adc_init(void) {
#define HAL_SENSITIVE_PINS 0, 1
#ifdef __AVR_AT90USB1286__
#define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
#endif
// AVR compatibility
#define strtof strtod
+3
View File
@@ -78,6 +78,8 @@
#error "SPINDLE_LASER_PWM_PIN is used by E3_AUTO_FAN_PIN."
#elif PIN_EXISTS(E4_AUTO_FAN) && SPINDLE_LASER_PWM_PIN == E4_AUTO_FAN_PIN
#error "SPINDLE_LASER_PWM_PIN is used by E4_AUTO_FAN_PIN."
#elif PIN_EXISTS(E5_AUTO_FAN) && SPINDLE_LASER_PWM_PIN == E5_AUTO_FAN_PIN
#error "SPINDLE_LASER_PWM_PIN is used by E5_AUTO_FAN_PIN."
#elif PIN_EXISTS(FAN) && SPINDLE_LASER_PWM_PIN == FAN_PIN
#error "SPINDLE_LASER_PWM_PIN is used FAN_PIN."
#elif PIN_EXISTS(FAN1) && SPINDLE_LASER_PWM_PIN == FAN1_PIN
@@ -106,6 +108,7 @@
|| defined(Y2_HARDWARE_SERIAL) \
|| defined(Z_HARDWARE_SERIAL ) \
|| defined(Z2_HARDWARE_SERIAL) \
|| defined(Z3_HARDWARE_SERIAL) \
|| defined(E0_HARDWARE_SERIAL) \
|| defined(E1_HARDWARE_SERIAL) \
|| defined(E2_HARDWARE_SERIAL) \
@@ -225,6 +225,26 @@ void setup_endstop_interrupts( void ) {
#endif
#endif
#if HAS_Z3_MAX
#if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT)
attachInterrupt(digitalPinToInterrupt(Z3_MAX_PIN), endstop_ISR, CHANGE);
#else
// Not all used endstop/probe -pins can raise interrupts. Please deactivate ENDSTOP_INTERRUPTS or change the pin configuration!
static_assert(digitalPinToPCICR(Z3_MAX_PIN) != NULL, "Z3_MAX_PIN is not interrupt-capable");
pciSetup(Z3_MAX_PIN);
#endif
#endif
#if HAS_Z3_MIN
#if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT)
attachInterrupt(digitalPinToInterrupt(Z3_MIN_PIN), endstop_ISR, CHANGE);
#else
// Not all used endstop/probe -pins can raise interrupts. Please deactivate ENDSTOP_INTERRUPTS or change the pin configuration!
static_assert(digitalPinToPCICR(Z3_MIN_PIN) != NULL, "Z3_MIN_PIN is not interrupt-capable");
pciSetup(Z3_MIN_PIN);
#endif
#endif
#if HAS_Z_MIN_PROBE_PIN
#if (digitalPinToInterrupt(Z_MIN_PROBE_PIN) != NOT_AN_INTERRUPT)
attachInterrupt(digitalPinToInterrupt(Z_MIN_PROBE_PIN), endstop_ISR, CHANGE);
@@ -0,0 +1,68 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../shared/persistent_store_api.h"
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
// EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v);
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((unsigned char*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false; // always assume success for AVR's
}
size_t PersistentStore::capacity() { return E2END + 1; }
#endif // EEPROM_SETTINGS
#endif // __AVR__
+2 -2
View File
@@ -60,8 +60,8 @@
#include <avr/interrupt.h>
#include <Arduino.h>
#include "../servo.h"
#include "../servo_private.h"
#include "../shared/servo.h"
#include "../shared/servo_private.h"
static volatile int8_t Channel[_Nbr_16timers]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
+2 -2
View File
@@ -26,8 +26,8 @@
#include "../../core/serial.h"
#include <stdarg.h>
#include "../backtrace/unwinder.h"
#include "../backtrace/unwmemaccess.h"
#include "../shared/backtrace/unwinder.h"
#include "../shared/backtrace/unwmemaccess.h"
// Debug monitor that dumps to the Programming port all status when
// an exception or WDT timeout happens - And then resets the board
+66 -99
View File
@@ -31,7 +31,7 @@
#ifdef ARDUINO_ARCH_SAM
#include "../persistent_store_api.h"
#include "../shared/persistent_store_api.h"
#include "../../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS) && DISABLED(I2C_EEPROM) && DISABLED(SPI_EEPROM)
@@ -41,7 +41,7 @@
#define EEPROMSize 4096
#define PagesPerGroup 128
#define GroupCount 2
#define PageSize 256
#define PageSize 256u
/* Flash storage */
typedef struct FLASH_SECTOR {
@@ -109,9 +109,9 @@ static const FLASH_SECTOR_T* getFlashStorage(int page) {
return (const FLASH_SECTOR_T*)&flashStorage[page*PageSize];
}
static uint8_t buffer[256] = {0}; // The RAM buffer to accumulate writes
static uint8_t curPage = 0; // Current FLASH page inside the group
static uint8_t curGroup = 0xFF; // Current FLASH group
static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes
curPage = 0, // Current FLASH page inside the group
curGroup = 0xFF; // Current FLASH group
//#define EE_EMU_DEBUG
#ifdef EE_EMU_DEBUG
@@ -125,12 +125,10 @@ static uint8_t curGroup = 0xFF; // Current FLASH group
char* p = &buffer[0];
for (int i = 0; i< PageSize; ++i) {
if ((i & 15) == 0) {
p += sprintf(p,"%04x] ",i);
}
if ((i & 0xF) == 0) p += sprintf(p,"%04x] ", i);
p += sprintf(p," %02x",c[i]);
if ((i & 15) == 15) {
p += sprintf(p," %02x", c[i]);
if ((i & 0xF) == 0xF) {
*p++ = '\n';
*p = 0;
SERIAL_PROTOCOL(buffer);
@@ -160,7 +158,7 @@ static uint8_t curGroup = 0xFF; // Current FLASH group
__attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageWrite(uint16_t page,const void* data) {
int i;
uint16_t i;
uint32_t addrflash = ((uint32_t)getFlashStorage(page));
// Read the flash contents
@@ -173,15 +171,14 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
// Programming mode works only with 128-bit (or higher) boundaries. It cannot
// be used with boundaries lower than 128 bits (8, 16 or 32-bit for example)."
// All bits that did not change, set them to 1.
for (i = 0; i <PageSize >> 2; i++) {
for (i = 0; i <PageSize >> 2; i++)
pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i]));
}
#ifdef EE_EMU_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("EEPROM PageWrite ",page);
SERIAL_ECHOLNPAIR(" in FLASH address ",(uint32_t)addrflash);
SERIAL_ECHOLNPAIR(" base address ",(uint32_t)getFlashStorage(0));
SERIAL_ECHOLNPAIR("EEPROM PageWrite ", page);
SERIAL_ECHOLNPAIR(" in FLASH address ", (uint32_t)addrflash);
SERIAL_ECHOLNPAIR(" base address ", (uint32_t)getFlashStorage(0));
SERIAL_FLUSH();
#endif
@@ -207,7 +204,7 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
// Set wait states to 6 (SAM errata)
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(6);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
// Unlock the flash page
uint32_t status;
@@ -220,14 +217,14 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(orgWS);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
#ifdef EE_EMU_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("EEPROM Unlock failure for page ",page);
SERIAL_ECHOLNPAIR("EEPROM Unlock failure for page ", page);
#endif
return false;
}
@@ -247,20 +244,20 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(orgWS);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
#ifdef EE_EMU_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("EEPROM Write failure for page ",page);
SERIAL_ECHOLNPAIR("EEPROM Write failure for page ", page);
#endif
return false;
}
// Restore original wait states
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(orgWS);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
@@ -270,7 +267,7 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
#ifdef EE_EMU_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("EEPROM Verify Write failure for page ",page);
SERIAL_ECHOLNPAIR("EEPROM Verify Write failure for page ", page);
ee_Dump( page,(uint32_t *) addrflash);
ee_Dump(-page,data);
@@ -289,7 +286,7 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
}
}
}
SERIAL_ECHOLNPAIR("--> Differing bits: ",count);
SERIAL_ECHOLNPAIR("--> Differing bits: ", count);
#endif
return false;
@@ -305,14 +302,14 @@ static bool ee_PageWrite(uint16_t page,const void* data) {
__attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageErase(uint16_t page) {
int i;
uint16_t i;
uint32_t addrflash = ((uint32_t)getFlashStorage(page));
#ifdef EE_EMU_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("EEPROM PageErase ",page);
SERIAL_ECHOLNPAIR(" in FLASH address ",(uint32_t)addrflash);
SERIAL_ECHOLNPAIR(" base address ",(uint32_t)getFlashStorage(0));
SERIAL_ECHOLNPAIR("EEPROM PageErase ", page);
SERIAL_ECHOLNPAIR(" in FLASH address ", (uint32_t)addrflash);
SERIAL_ECHOLNPAIR(" base address ", (uint32_t)getFlashStorage(0));
SERIAL_FLUSH();
#endif
@@ -338,7 +335,7 @@ static bool ee_PageErase(uint16_t page) {
uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
// Set wait states to 6 (SAM errata)
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(6);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
// Unlock the flash page
uint32_t status;
@@ -350,7 +347,7 @@ static bool ee_PageErase(uint16_t page) {
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(orgWS);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
@@ -375,7 +372,7 @@ static bool ee_PageErase(uint16_t page) {
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(orgWS);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
@@ -388,7 +385,7 @@ static bool ee_PageErase(uint16_t page) {
}
// Restore original wait states
efc->EEFC_FMR = efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(orgWS);
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
@@ -421,7 +418,7 @@ static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer = false) {
// Check that the value is not contained in the RAM buffer
if (!excludeRAMBuffer) {
int i = 0;
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
@@ -462,7 +459,7 @@ static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer = false) {
// Get a pointer to the flash page
uint8_t* pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
int i = 0;
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
@@ -476,18 +473,13 @@ static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer = false) {
break;
// Check if data is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Return it!
return pflash[i + 3 + address - baddr];
}
if (address >= baddr && address < (baddr + blen))
return pflash[i + 3 + address - baddr]; // Yes, it is contained. Return it!
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address)
break;
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
@@ -499,14 +491,14 @@ static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer = false) {
}
static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false) {
uint32_t baddr;
uint32_t blen;
uint32_t nextAddr = 0xFFFF;
uint32_t nextRange = 0;
uint32_t baddr,
blen,
nextAddr = 0xFFFF,
nextRange = 0;
// Check that the value is not contained in the RAM buffer
if (!excludeRAMBuffer) {
int i = 0;
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
@@ -516,16 +508,11 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false)
blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
if (blen == 0xFF) break;
// Check if address and address + 1 is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Return it!
return address | ((blen - address + baddr) << 16);
}
if (address >= baddr && address < (baddr + blen))
return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
// Otherwise, check if we can use it as a limit
if (baddr > address && baddr < nextAddr) {
@@ -536,8 +523,7 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false)
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address)
break;
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
@@ -553,7 +539,7 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false)
// Get a pointer to the flash page
uint8_t* pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
int i = 0;
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
@@ -563,16 +549,11 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false)
blen = pflash[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
if (blen == 0xFF) break;
// Check if data is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Return it!
return address | ((blen - address + baddr) << 16);
}
if (address >= baddr && address < (baddr + blen))
return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
// Otherwise, check if we can use it as a limit
if (baddr > address && baddr < nextAddr) {
@@ -583,8 +564,7 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false)
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address)
break;
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
@@ -596,12 +576,9 @@ static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer = false)
}
static bool ee_IsPageClean(int page) {
uint32_t* pflash = (uint32_t*) getFlashStorage(page);
for (int i = 0; i < (PageSize >> 2); ++i) {
if (*pflash++ != 0xFFFFFFFF)
return false;
}
for (uint16_t i = 0; i < (PageSize >> 2); ++i)
if (*pflash++ != 0xFFFFFFFF) return false;
return true;
}
@@ -610,7 +587,7 @@ static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData
// Check if RAM buffer has something to be written
bool isEmpty = true;
uint32_t* p = (uint32_t*) &buffer[0];
for (int j = 0; j < (PageSize >> 2); j++) {
for (uint16_t j = 0; j < (PageSize >> 2); j++) {
if (*p++ != 0xFFFFFFFF) {
isEmpty = false;
break;
@@ -648,13 +625,11 @@ static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData
}
// We have no space left on the current group - We must compact the values
int i = 0;
uint16_t i = 0;
// Compute the next group to use
int curwPage = 0;
int curwGroup = curGroup + 1;
if (curwGroup >= GroupCount)
curwGroup = 0;
int curwPage = 0, curwGroup = curGroup + 1;
if (curwGroup >= GroupCount) curwGroup = 0;
uint32_t rdAddr = 0;
do {
@@ -774,12 +749,11 @@ static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData
static bool ee_Write(uint32_t address, uint8_t data) {
// If we were requested an address outside of the emulated range, fail now
if (address >= EEPROMSize)
return false;
if (address >= EEPROMSize) return false;
// Lets check if we have a block with that data previously defined. Block
// start addresses are always sorted in ascending order
int i = 0;
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
@@ -805,8 +779,7 @@ static bool ee_Write(uint32_t address, uint8_t data) {
// Maybe we could add it to the front or to the back
// of this block ?
if ((address + 1) == baddr ||
address == (baddr + blen)) {
if ((address + 1) == baddr || address == (baddr + blen)) {
// Potentially, it could be done. But we must ensure there is room
// so we can expand the block. Lets find how much free space remains
@@ -840,9 +813,9 @@ static bool ee_Write(uint32_t address, uint8_t data) {
// Insert at the end - There is a very interesting thing that could happen here:
// Maybe we could coalesce the next block with this block. Let's try to do it!
int inext = i + 3 + blen;
uint16_t inext = i + 3 + blen;
if (inext <= (PageSize - 4) &&
(buffer[inext] | (buffer[inext + 1] << 8)) == (baddr + blen + 1)) {
(buffer[inext] | uint16_t(buffer[inext + 1] << 8)) == (baddr + blen + 1)) {
// YES! ... we can coalesce blocks! . Do it!
// Adjust this block header to include the next one
@@ -879,8 +852,7 @@ static bool ee_Write(uint32_t address, uint8_t data) {
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address)
break;
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
@@ -924,21 +896,17 @@ static bool ee_Write(uint32_t address, uint8_t data) {
static void ee_Init() {
// Just init once!
if (curGroup != 0xFF)
return;
if (curGroup != 0xFF) return;
// Clean up the SRAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Now, we must find out the group where settings are stored
for (curGroup = 0; curGroup < GroupCount; curGroup++) {
if (!ee_IsPageClean(curGroup * PagesPerGroup))
break;
}
for (curGroup = 0; curGroup < GroupCount; curGroup++)
if (!ee_IsPageClean(curGroup * PagesPerGroup)) break;
// If all groups seem to be used, default to first group
if (curGroup >= GroupCount)
curGroup = 0;
if (curGroup >= GroupCount) curGroup = 0;
#ifdef EE_EMU_DEBUG
SERIAL_ECHO_START();
@@ -948,8 +916,7 @@ static void ee_Init() {
// Now, validate that all the other group pages are empty
for (int grp = 0; grp < GroupCount; grp++) {
if (grp == curGroup)
continue;
if (grp == curGroup) continue;
for (int page = 0; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(grp * PagesPerGroup + page)) {
@@ -1031,4 +998,4 @@ void eeprom_flush(void) {
}
#endif // ENABLED(EEPROM_SETTINGS) && DISABLED(I2C_EEPROM) && DISABLED(SPI_EEPROM)
#endif // ARDUINO_ARCH_AVR
#endif // ARDUINO_ARCH_AVR
+2 -2
View File
@@ -35,8 +35,8 @@
#include <Arduino.h>
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio_Due.h"
#include "watchdog_Due.h"
#include "HAL_timers_Due.h"
+1 -1
View File
@@ -42,7 +42,7 @@
// --------------------------------------------------------------------------
#include "../../inc/MarlinConfig.h"
#include "../Delay.h"
#include "../shared/Delay.h"
// --------------------------------------------------------------------------
// Public Variables
-6
View File
@@ -109,12 +109,6 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_CV;
}
// if counter too high then bump up compare
FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
}
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
+2 -3
View File
@@ -45,8 +45,8 @@
#if HAS_SERVOS
#include <Arduino.h>
#include "../servo.h"
#include "../servo_private.h"
#include "../shared/servo.h"
#include "../shared/servo_private.h"
static volatile int8_t Channel[_Nbr_16timers]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
@@ -158,4 +158,3 @@ void finISR(timer16_Sequence_t timer) {
#endif // HAS_SERVOS
#endif // ARDUINO_ARCH_SAM
@@ -72,6 +72,12 @@ void setup_endstop_interrupts(void) {
#if HAS_Z2_MIN
attachInterrupt(digitalPinToInterrupt(Z2_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(digitalPinToInterrupt(Z3_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(digitalPinToInterrupt(Z3_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(digitalPinToInterrupt(Z_MIN_PROBE_PIN), endstop_ISR, CHANGE);
#endif
@@ -0,0 +1,82 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../../inc/MarlinConfig.h"
#include "../shared/persistent_store_api.h"
#if DISABLED(I2C_EEPROM) && DISABLED(SPI_EEPROM)
#define E2END 0xFFF // Default to Flash emulated EEPROM size (EepromEmulation_Due.cpp)
#endif
extern void eeprom_flush(void);
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() {
#if DISABLED(I2C_EEPROM) && DISABLED(SPI_EEPROM)
eeprom_flush();
#endif
return true;
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
// EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v);
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((unsigned char*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
size_t PersistentStore::capacity() { return E2END + 1; }
#endif // EEPROM_SETTINGS
#endif // ARDUINO_ARCH_SAM
@@ -61,7 +61,7 @@
#include <U8glib.h>
#include <Arduino.h>
#include "../Delay.h"
#include "../shared/Delay.h"
void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index) {
PIO_Configure(g_APinDescription[u8g->pin_list[pin_index]].pPort, PIO_OUTPUT_1,
+2 -2
View File
@@ -40,8 +40,8 @@
#undef DISABLED
#define DISABLED(b) (!_CAT(SWITCH_ENABLED_, b))
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio_ESP32.h"
#include "watchdog_ESP32.h"
+1 -1
View File
@@ -28,7 +28,7 @@
// --------------------------------------------------------------------------
#include "HAL.h"
#include "../HAL_SPI.h"
#include "../shared/HAL_SPI.h"
#include "pins_arduino.h"
#include "spi_pins.h"
#include "../../core/macros.h"
@@ -98,12 +98,6 @@ void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t count);
hal_timer_t HAL_timer_get_compare(const uint8_t timer_num);
hal_timer_t HAL_timer_get_count(const uint8_t timer_num);
// if counter too high then bump up compare
FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
}
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
@@ -67,6 +67,12 @@ void setup_endstop_interrupts(void) {
#if HAS_Z2_MIN
attachInterrupt(digitalPinToInterrupt(Z2_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(digitalPinToInterrupt(Z3_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(digitalPinToInterrupt(Z3_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(digitalPinToInterrupt(Z_MIN_PROBE_PIN), endstop_ISR, CHANGE);
#endif
+7 -7
View File
@@ -21,7 +21,7 @@
#ifdef TARGET_LPC1768
#include "../../inc/MarlinConfig.h"
#include "../Delay.h"
#include "../shared/Delay.h"
HalSerial usb_serial;
@@ -125,13 +125,13 @@ bool HAL_adc_finished(void) {
// possible config options if something similar is extended to more platforms.
#define ADC_USE_MEDIAN_FILTER // Filter out erroneous readings
#define ADC_MEDIAN_FILTER_SIZE (23) // Higher values increase step delay (phase shift),
#define ADC_MEDIAN_FILTER_SIZE 23 // Higher values increase step delay (phase shift),
// (ADC_MEDIAN_FILTER_SIZE + 1) / 2 sample step delay (12 samples @ 500Hz: 24ms phase shift)
// Memory usage per ADC channel (bytes): (6 * ADC_MEDIAN_FILTER_SIZE) + 16
// 8 * ((6 * 23) + 16 ) = 1232 Bytes for 8 channels
#define ADC_USE_LOWPASS_FILTER // Filter out high frequency noise
#define ADC_LOWPASS_K_VALUE (6) // Higher values increase rise time
#define ADC_LOWPASS_K_VALUE 6 // Higher values increase rise time
// Rise time sample delays for 100% signal convergence on full range step
// (1 : 13, 2 : 32, 3 : 67, 4 : 139, 5 : 281, 6 : 565, 7 : 1135, 8 : 2273)
// K = 6, 565 samples, 500Hz sample rate, 1.13s convergence on full range step
@@ -162,7 +162,7 @@ struct MedianFilter {
datum = STOPPER + 1; // No stoppers allowed.
}
if ( (++datpoint - buffer) >= ADC_MEDIAN_FILTER_SIZE) {
if ( (++datpoint - buffer) >= (ADC_MEDIAN_FILTER_SIZE)) {
datpoint = buffer; // Increment and wrap data in pointer.
}
@@ -224,9 +224,9 @@ struct MedianFilter {
struct LowpassFilter {
uint32_t data_delay = 0;
uint16_t update(uint16_t value) {
data_delay = data_delay - (data_delay >> ADC_LOWPASS_K_VALUE) + value;
return (uint16_t)(data_delay >> ADC_LOWPASS_K_VALUE);
uint16_t update(const uint16_t value) {
data_delay -= (data_delay >> (ADC_LOWPASS_K_VALUE)) - value;
return (uint16_t)(data_delay >> (ADC_LOWPASS_K_VALUE));
}
};
+2 -2
View File
@@ -60,8 +60,8 @@ extern "C" volatile uint32_t _millis;
#include <Arduino.h>
#include <pinmapping.h>
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include "watchdog.h"
#include "serial.h"
-5
View File
@@ -127,11 +127,6 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
return 0;
}
FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
}
FORCE_INLINE static void HAL_timer_enable_interrupt(const uint8_t timer_num) {
switch (timer_num) {
case 0: NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
+1 -1
View File
@@ -26,7 +26,7 @@
#include <lpc17xx_pinsel.h>
#include "../../inc/MarlinConfig.h"
#include "../Delay.h"
#include "../shared/Delay.h"
// Interrupts
void cli(void) { __disable_irq(); } // Disable
@@ -91,6 +91,12 @@ void setup_endstop_interrupts(void) {
#endif
attachInterrupt(digitalPinToInterrupt(Z2_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(digitalPinToInterrupt(Z3_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(digitalPinToInterrupt(Z3_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
#if !LPC1768_PIN_INTERRUPT_M(Z_MIN_PROBE_PIN)
#error "Z_MIN_PROBE_PIN is not an INTERRUPT capable pin."
@@ -43,8 +43,6 @@
#define FALLING 0x03
#define RISING 0x04
#define E2END 0xFFF // EEPROM end address
typedef uint8_t byte;
#define PROGMEM
#define PSTR(v) (v)
+1 -1
View File
@@ -22,7 +22,7 @@
#pragma once
#include "../../HAL_SPI.h"
#include "../../shared/HAL_SPI.h"
#include <stdint.h>
@@ -37,7 +37,7 @@
//
//#include <WInterrupts.h>
#include "../../../inc/MarlinConfig.h"
#include "../../Delay.h"
#include "../../shared/Delay.h"
#include <stdint.h>
#include <stdarg.h>
#include <Arduino.h>
+10 -10
View File
@@ -7,7 +7,7 @@ extern void setup();
extern void loop();
extern "C" {
#include <lpc17xx_gpio.h>
#include <lpc17xx_gpio.h>
}
#include <usb/usb.h>
@@ -19,9 +19,9 @@ extern "C" {
#include <usb/mscuser.h>
extern "C" {
#include <debug_frmwrk.h>
#include <chanfs/diskio.h>
#include <chanfs/ff.h>
#include <debug_frmwrk.h>
#include <chanfs/diskio.h>
#include <chanfs/ff.h>
}
#include "../../inc/MarlinConfig.h"
@@ -59,15 +59,15 @@ extern "C" {
// Runs after clock init and before global static constructors
void SystemPostInit() {
_millis = 0; // Initialise the millisecond counter value;
_millis = 0; // Initialize the millisecond counter value
SysTick_Config(SystemCoreClock / 1000); // Start millisecond global counter
// Runs before setup() need to configure LED_PIN and use to indicate succsessful bootloader execution
// Runs before setup() to configure LED_PIN and used to indicate successful bootloader execution
#if PIN_EXISTS(LED)
SET_DIR_OUTPUT(LED_PIN);
WRITE_PIN_CLR(LED_PIN);
//MKS-SBASE has 3 other LEDS the bootloader uses during flashing, clear them
// MKS_SBASE has 3 other LEDs the bootloader uses during flashing. Clear them.
SET_DIR_OUTPUT(P1_19);
WRITE_PIN_CLR(P1_19);
SET_DIR_OUTPUT(P1_20);
@@ -75,7 +75,7 @@ extern "C" {
SET_DIR_OUTPUT(P1_21);
WRITE_PIN_CLR(P1_21);
for (int i = 0; i < 6; ++i) {
for (uint8_t i = 6; i--;) {
TOGGLE(LED_PIN);
delay(100);
}
@@ -96,7 +96,7 @@ int main(void) {
while (!USB_Configuration && PENDING(millis(), usb_timeout)) {
delay(50);
#if PIN_EXISTS(LED)
TOGGLE(LED_PIN); // Flash fast while USB initialisation completes
TOGGLE(LED_PIN); // Flash quickly during USB initialization
#endif
}
@@ -105,7 +105,7 @@ int main(void) {
#if NUM_SERIAL > 1
MYSERIAL1.begin(BAUDRATE);
#endif
SERIAL_PRINTF("\n\necho:%s (%dMhz) Initialised\n", isLPC1769() ? "LPC1769" : "LPC1768", SystemCoreClock / 1000000);
SERIAL_PRINTF("\n\necho:%s (%dMhz) Initialized\n", isLPC1769() ? "LPC1769" : "LPC1768", SystemCoreClock / 1000000);
SERIAL_FLUSHTX();
#endif
@@ -0,0 +1,24 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 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 <http://www.gnu.org/licenses/>.
*
*/
#include "../shared/persistent_store_api.h"
//#define FLASH_EEPROM
@@ -0,0 +1,138 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef TARGET_LPC1768
/**
* Emulate EEPROM storage using Flash Memory
*
* Use a single 32K flash sector to store EEPROM data. To reduce the
* number of erase operations a simple "levelling" scheme is used that
* maintains a number of EEPROM "slots" within the larger flash sector.
* Each slot is used in turn and the entire sector is only erased when all
* slots have been used.
*
* A simple RAM image is used to hold the EEPROM data during I/O operations
* and this is flushed to the next available slot when an update is complete.
* If RAM usage becomes an issue we could store this image in one of the two
* 16Kb I/O buffers (intended to hold DMA USB and Ethernet data, but currently
* unused).
*/
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EEPROM_SETTINGS)
#include "persistent_store_api.h"
#include "../../inc/MarlinConfig.h"
#if ENABLED(FLASH_EEPROM)
extern "C" {
#include "lpc17xx_iap.h"
}
#define SECTOR_START(sector) ((sector < 16) ? (sector * 0x1000) : ((sector - 14) * 0x8000))
#define EEPROM_SECTOR 29
#define EEPROM_SIZE (4096)
#define SECTOR_SIZE (32768)
#define EEPROM_SLOTS (SECTOR_SIZE/EEPROM_SIZE)
#define EEPROM_ERASE (0xff)
#define SLOT_ADDRESS(sector, slot) (((uint8_t *)SECTOR_START(sector)) + slot * EEPROM_SIZE)
static uint8_t ram_eeprom[EEPROM_SIZE];
static bool eeprom_dirty = false;
static int current_slot = 0;
bool PersistentStore::access_start() {
uint32_t first_nblank_loc, first_nblank_val;
IAP_STATUS_CODE status;
// discover which slot we are currently using.
__disable_irq();
status = BlankCheckSector(EEPROM_SECTOR, EEPROM_SECTOR, &first_nblank_loc, &first_nblank_val);
__enable_irq();
SERIAL_PROTOCOLLNPAIR("Blank check status: ", status);
if (status == CMD_SUCCESS) {
// sector is blank so nothing stored yet
SERIAL_PROTOCOLLNPGM("FLASH empty");
for (int i = 0; i < EEPROM_SIZE; i++) ram_eeprom[i] = EEPROM_ERASE;
current_slot = EEPROM_SLOTS;
}
else {
// current slot is the first non blank one
current_slot = first_nblank_loc / EEPROM_SIZE;
SERIAL_PROTOCOLLNPAIR("Flash slot: ", current_slot);
uint8_t *eeprom_data = SLOT_ADDRESS(EEPROM_SECTOR, current_slot);
SERIAL_PROTOCOLLNPAIR("Address: ", (int)eeprom_data);
// load current settings
for (int i = 0; i < EEPROM_SIZE; i++) ram_eeprom[i] = eeprom_data[i];
}
eeprom_dirty = false;
return true;
}
bool PersistentStore::access_finish() {
if (eeprom_dirty) {
IAP_STATUS_CODE status;
if (--current_slot < 0) {
// all slots have been used, erase everything and start again
__disable_irq();
PrepareSector(EEPROM_SECTOR, EEPROM_SECTOR);
status = EraseSector(EEPROM_SECTOR, EEPROM_SECTOR);
__enable_irq();
SERIAL_PROTOCOLLNPAIR("Erase status: ", status);
current_slot = EEPROM_SLOTS - 1;
}
SERIAL_PROTOCOLLNPAIR("Writing data to: ", current_slot);
__disable_irq();
PrepareSector(EEPROM_SECTOR, EEPROM_SECTOR);
status = CopyRAM2Flash(SLOT_ADDRESS(EEPROM_SECTOR, current_slot), ram_eeprom, IAP_WRITE_4096);
__enable_irq();
SERIAL_PROTOCOLLNPAIR("CopyRAM2Flash status: ", status);
if (status != CMD_SUCCESS) return false;
eeprom_dirty = false;
}
return true;
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
for (int i = 0; i < size; i++) ram_eeprom[pos + i] = value[i];
eeprom_dirty = true;
crc16(crc, value, size);
pos += size;
return false; // return true for any error
}
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
const uint8_t * const buff = writing ? &value[0] : &ram_eeprom[pos];
if (writing) for (int i = 0; i < size; i++) value[i] = ram_eeprom[pos + i];
crc16(crc, buff, size);
pos += size;
return false; // return true for any error
}
size_t PersistentStore::capacity() { return EEPROM_SIZE; }
#endif // FLASH_EEPROM
#endif // EEPROM_SETTINGS
#endif // TARGET_LPC1768
@@ -0,0 +1,183 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef TARGET_LPC1768
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../../inc/MarlinConfig.h"
#include "persistent_store_api.h"
#if DISABLED(FLASH_EEPROM)
#include <chanfs/diskio.h>
#include <chanfs/ff.h>
extern uint32_t MSC_Aquire_Lock();
extern uint32_t MSC_Release_Lock();
FATFS fat_fs;
FIL eeprom_file;
bool eeprom_file_open = false;
bool PersistentStore::access_start() {
const char eeprom_erase_value = 0xFF;
MSC_Aquire_Lock();
if (f_mount(&fat_fs, "", 1)) {
MSC_Release_Lock();
return false;
}
FRESULT res = f_open(&eeprom_file, "eeprom.dat", FA_OPEN_ALWAYS | FA_WRITE | FA_READ);
if (res) MSC_Release_Lock();
if (res == FR_OK) {
UINT bytes_written;
FSIZE_t file_size = f_size(&eeprom_file);
f_lseek(&eeprom_file, file_size);
while (file_size < capacity() && res == FR_OK) {
res = f_write(&eeprom_file, &eeprom_erase_value, 1, &bytes_written);
file_size++;
}
}
if (res == FR_OK) {
f_lseek(&eeprom_file, 0);
f_sync(&eeprom_file);
eeprom_file_open = true;
}
return res == FR_OK;
}
bool PersistentStore::access_finish() {
f_close(&eeprom_file);
f_unmount("");
MSC_Release_Lock();
eeprom_file_open = false;
return true;
}
// This extra chit-chat goes away soon, but is helpful for now
// to see errors that are happening in read_data / write_data
static void debug_rw(const bool write, int &pos, const uint8_t *value, const size_t size, const FRESULT s, const size_t total=0) {
const char * const rw_str = write ? PSTR("write") : PSTR("read");
SERIAL_PROTOCOLCHAR(' ');
serialprintPGM(rw_str);
SERIAL_PROTOCOLPAIR("_data(", pos);
SERIAL_PROTOCOLPAIR(",", (int)value);
SERIAL_PROTOCOLPAIR(",", (int)size);
SERIAL_PROTOCOLLNPGM(", ...)");
if (total) {
SERIAL_PROTOCOLPGM(" f_");
serialprintPGM(rw_str);
SERIAL_PROTOCOLPAIR("()=", (int)s);
SERIAL_PROTOCOLPAIR("\n size=", size);
SERIAL_PROTOCOLPGM("\n bytes_");
serialprintPGM(write ? PSTR("written=") : PSTR("read="));
SERIAL_PROTOCOLLN(total);
}
else
SERIAL_PROTOCOLLNPAIR(" f_lseek()=", (int)s);
}
// File function return codes for type FRESULT. This goes away soon, but
// is helpful right now to see any errors in read_data and write_data.
//
// typedef enum {
// FR_OK = 0, /* (0) Succeeded */
// FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
// FR_INT_ERR, /* (2) Assertion failed */
// FR_NOT_READY, /* (3) The physical drive cannot work */
// FR_NO_FILE, /* (4) Could not find the file */
// FR_NO_PATH, /* (5) Could not find the path */
// FR_INVALID_NAME, /* (6) The path name format is invalid */
// FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
// FR_EXIST, /* (8) Access denied due to prohibited access */
// FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
// FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
// FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
// FR_NOT_ENABLED, /* (12) The volume has no work area */
// FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
// FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
// FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
// FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
// FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
// FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
// FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
// } FRESULT;
bool PersistentStore::write_data(int &pos, const uint8_t *value, const size_t size, uint16_t *crc) {
if (!eeprom_file_open) return true;
FRESULT s;
UINT bytes_written = 0;
s = f_lseek(&eeprom_file, pos);
if (s) {
debug_rw(true, pos, value, size, s);
return s;
}
s = f_write(&eeprom_file, (void*)value, size, &bytes_written);
if (s) {
debug_rw(true, pos, value, size, s, bytes_written);
return s;
}
crc16(crc, value, size);
pos += size;
return bytes_written != size; // return true for any error
}
bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
if (!eeprom_file_open) return true;
UINT bytes_read = 0;
FRESULT s;
s = f_lseek(&eeprom_file, pos);
if (s) {
debug_rw(false, pos, value, size, s);
return true;
}
if (writing) {
s = f_read(&eeprom_file, (void*)value, size, &bytes_read);
crc16(crc, value, size);
}
else {
uint8_t temp[size];
s = f_read(&eeprom_file, (void*)temp, size, &bytes_read);
crc16(crc, temp, size);
}
if (s) {
debug_rw(false, pos, value, size, s, bytes_read);
return true;
}
pos += size;
return bytes_read != size; // return true for any error
}
size_t PersistentStore::capacity() { return 4096; } // 4KiB of Emulated EEPROM
#endif // !FLASH_EEPROM
#endif // EEPROM_SETTINGS
#endif // TARGET_LPC1768
@@ -61,7 +61,7 @@
//#include <inttypes.h>
#include <U8glib.h>
#include "../Delay.h"
#include "../shared/Delay.h"
#define SPI_FULL_SPEED 0
#define SPI_HALF_SPEED 1
@@ -61,7 +61,7 @@
#include <U8glib.h>
#include "SoftwareSPI.h"
#include "../Delay.h"
#include "../shared/Delay.h"
#define SPI_SPEED 3 // About 1 MHz
+5 -3
View File
@@ -40,7 +40,7 @@
// --------------------------------------------------------------------------
#include <stdint.h>
#include <libmaple/atomic.h>
#include <util/atomic.h>
#include <Arduino.h>
// --------------------------------------------------------------------------
@@ -56,8 +56,8 @@
// Includes
// --------------------------------------------------------------------------
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio_Stm32f1.h"
#include "watchdog_Stm32f1.h"
@@ -249,4 +249,6 @@ void HAL_enable_AdcFreerun(void);
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
#define JTAG_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_NONE)
#endif // _HAL_STM32F1_H
@@ -27,22 +27,88 @@
#if HAS_SERVOS
uint8_t ServoCount; //=0
#include "HAL_Servo_Stm32f1.h"
int8_t libServo::attach(const int pin) {
if (this->servoIndex >= MAX_SERVOS) return -1;
return Servo::attach(pin);
//#include "Servo.h"
#include <boards.h>
#include <io.h>
#include <pwm.h>
#include <wirish_math.h>
/**
* 20 millisecond period config. For a 1-based prescaler,
*
* (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
* => prescaler * overflow = 20 * CYC_MSEC
*
* This uses the smallest prescaler that allows an overflow < 2^16.
*/
#define MAX_OVERFLOW ((1 << 16) - 1)
#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
#define TAU_MSEC 20
#define TAU_USEC (TAU_MSEC * 1000)
#define TAU_CYC (TAU_MSEC * CYC_MSEC)
#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER))
// Unit conversions
#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \
SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW)))
#define US_TO_ANGLE(us) ((int16)(map((us), SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW, \
this->minAngle, this->maxAngle)))
libServo::libServo() {
this->servoIndex = ServoCount < MAX_SERVOS ? ServoCount++ : INVALID_SERVO;
}
int8_t libServo::attach(const int pin, const int min, const int max) {
return Servo::attach(pin, min, max);
bool libServo::attach(const int32_t pin, const int32_t minAngle, const int32_t maxAngle) {
if (this->servoIndex >= MAX_SERVOS) return false;
this->pin = pin;
this->minAngle = minAngle;
this->maxAngle = maxAngle;
timer_dev *tdev = PIN_MAP[this->pin].timer_device;
uint8 tchan = PIN_MAP[this->pin].timer_channel;
pinMode(this->pin, PWM);
pwmWrite(this->pin, 0);
timer_pause(tdev);
timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
timer_set_reload(tdev, SERVO_OVERFLOW);
timer_generate_update(tdev);
timer_resume(tdev);
return true;
}
void libServo::move(const int value) {
bool libServo::detach() {
if (!this->attached()) return false;
pwmWrite(this->pin, 0);
return true;
}
int32_t libServo::read() const {
if (this->attached()) {
timer_dev *tdev = PIN_MAP[this->pin].timer_device;
uint8 tchan = PIN_MAP[this->pin].timer_channel;
return US_TO_ANGLE(COMPARE_TO_US(timer_get_compare(tdev, tchan)));
}
return 0;
}
void libServo::move(const int32_t value) {
constexpr uint16_t servo_delay[] = SERVO_DELAY;
static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
if (this->attach(0) >= 0) {
this->write(value);
if (this->attached()) {
pwmWrite(this->pin, US_TO_COMPARE(ANGLE_TO_US(constrain(value, this->minAngle, this->maxAngle))));
safe_delay(servo_delay[this->servoIndex]);
#if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE)
this->detach();
+26 -11
View File
@@ -24,19 +24,34 @@
#ifndef HAL_SERVO_STM32F1_H
#define HAL_SERVO_STM32F1_H
// Path needed, otherwise HAL version is used
#include <../../libraries/Servo/src/Servo.h>
// Pin number of unattached pins
#define NOT_ATTACHED (-1)
#define INVALID_SERVO 255
// Inherit and expand on the official library
class libServo : public Servo {
public:
int8_t attach(const int pin);
int8_t attach(const int pin, const int min, const int max);
void move(const int value);
private:
uint16_t min_ticks;
uint16_t max_ticks;
#ifndef MAX_SERVOS
#define MAX_SERVOS 3
#endif
#define SERVO_DEFAULT_MIN_PW 544
#define SERVO_DEFAULT_MAX_PW 2400
#define SERVO_DEFAULT_MIN_ANGLE 0
#define SERVO_DEFAULT_MAX_ANGLE 180
#define HAL_SERVO_LIB libServo
class libServo {
public:
libServo();
bool attach(const int32_t pin, const int32_t minAngle=SERVO_DEFAULT_MIN_ANGLE, const int32_t maxAngle=SERVO_DEFAULT_MAX_ANGLE);
bool attached() const { return this->pin != NOT_ATTACHED; }
bool detach();
void move(const int32_t value);
int32_t read() const;
private:
uint8_t servoIndex; // index into the channel data for this servo
int32_t pin = NOT_ATTACHED;
int32_t minAngle;
int32_t maxAngle;
};
#endif // HAL_SERVO_STM32F1_H
@@ -37,7 +37,7 @@
// --------------------------------------------------------------------------
#include "HAL.h"
#include "../HAL_SPI.h"
#include "../shared/HAL_SPI.h"
#include "pins_arduino.h"
#include "spi_pins.h"
#include "../../core/macros.h"
@@ -81,8 +81,8 @@ void spiBegin() {
#if !PIN_EXISTS(SS)
#error "SS_PIN not defined!"
#endif
WRITE(SS_PIN, HIGH);
SET_OUTPUT(SS_PIN);
WRITE(SS_PIN, HIGH);
}
/**
@@ -104,7 +104,7 @@ void spiInit(uint8_t spiRate) {
case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break;
default: clock = SPI_CLOCK_DIV2; // Default from the SPI library
}
spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE3);
SPI.begin();
}
@@ -151,11 +151,6 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
}
}
FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
}
FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
switch (timer_num) {
case STEP_TIMER_NUM:
+1
View File
@@ -0,0 +1 @@
#include "bit_constants.h"
@@ -79,6 +79,12 @@ void setup_endstop_interrupts(void) {
#if HAS_Z2_MIN
attachInterrupt(Z2_MIN_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(Z3_MAX_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(Z3_MIN_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(Z_MIN_PROBE_PIN, endstop_ISR, CHANGE);
#endif
@@ -34,33 +34,28 @@
// This is for EEPROM emulation in flash
#if ENABLED(EEPROM_SETTINGS) && ENABLED(FLASH_EEPROM_EMULATION)
#include "../persistent_store_api.h"
#include "../shared/persistent_store_api.h"
#include <flash_stm32.h>
#include <EEPROM.h>
namespace HAL {
namespace PersistentStore {
// Store settings in the last two pages
// Flash pages must be erased before writing, so keep track.
bool firstWrite = false;
uint32_t pageBase = EEPROM_START_ADDRESS;
namespace {
// Store settings in the last two pages
// Flash pages must be erased before writing, so keep track.
bool firstWrite = false;
uint32_t pageBase = EEPROM_START_ADDRESS;
}
bool access_start() {
bool PersistentStore::access_start() {
firstWrite = true;
return true;
}
bool access_finish() {
bool PersistentStore::access_finish() {
FLASH_Lock();
firstWrite = false;
return true;
}
bool write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
bool PersistentStore::write_data(int &pos, const uint8_t *value, const size_t size, uint16_t *crc) {
FLASH_Status status;
if (firstWrite) {
@@ -95,7 +90,7 @@ bool write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
return false;
}
bool read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc, const bool writing/*=true*/) {
bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
for (uint16_t i = 0; i < size; i++) {
byte* accessPoint = (byte*)(pageBase + pos + i);
uint8_t c = *accessPoint;
@@ -106,8 +101,7 @@ bool read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc, const boo
return false;
}
} // PersistentStore
} // HAL
size_t PersistentStore::capacity() { return E2END + 1; }
#endif // EEPROM_SETTINGS && EEPROM FLASH
#endif // __STM32F1__
@@ -0,0 +1,86 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* HAL for stm32duino.com based on Libmaple and compatible (STM32F1)
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS) && DISABLED(FLASH_EEPROM_EMULATION)
#include "../shared/persistent_store_api.h"
#include "../../sd/cardreader.h"
#define HAL_STM32F1_EEPROM_SIZE 4096
char HAL_STM32F1_eeprom_content[HAL_STM32F1_EEPROM_SIZE];
char eeprom_filename[] = "eeprom.dat";
bool PersistentStore::access_start() {
if (!card.cardOK) return false;
int16_t bytes_read = 0;
constexpr char eeprom_zero = 0xFF;
card.openFile(eeprom_filename, true);
bytes_read = card.read(HAL_STM32F1_eeprom_content, HAL_STM32F1_EEPROM_SIZE);
if (bytes_read < 0) return false;
for (; bytes_read < HAL_STM32F1_EEPROM_SIZE; bytes_read++)
HAL_STM32F1_eeprom_content[bytes_read] = eeprom_zero;
card.closefile();
return true;
}
bool PersistentStore::access_finish() {
if (!card.cardOK) return false;
card.openFile(eeprom_filename, true);
int16_t bytes_written = card.write(HAL_STM32F1_eeprom_content, HAL_STM32F1_EEPROM_SIZE);
card.closefile();
return (bytes_written == HAL_STM32F1_EEPROM_SIZE);
}
bool PersistentStore::write_data(int &pos, const uint8_t *value, const size_t size, uint16_t *crc) {
for (int i = 0; i < size; i++)
HAL_STM32F1_eeprom_content[pos + i] = value[i];
crc16(crc, value, size);
pos += size;
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
for (int i = 0; i < size; i++) {
uint8_t c = HAL_STM32F1_eeprom_content[pos + i];
if (writing) value[i] = c;
crc16(crc, &c, 1);
}
pos += size;
return false;
}
size_t PersistentStore::capacity() { return HAL_STM32F1_EEPROM_SIZE; }
#endif // EEPROM_SETTINGS
#endif // __STM32F1__
@@ -78,7 +78,7 @@ static uint16_t EE_VerifyPageFullyErased(uint32_t Address);
* @retval - Flash error code: on write Flash error
* - FLASH_COMPLETE: on success
*/
uint16_t EE_Initialise(void) {
uint16_t EE_Initialize(void) {
uint16_t PageStatus0 = 6, PageStatus1 = 6;
uint16_t VarIdx = 0;
uint16_t EepromStatus = 0, ReadStatus = 0;
@@ -108,7 +108,7 @@
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
uint16_t EE_Initialise(void);
uint16_t EE_Initialize(void);
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);
@@ -59,7 +59,7 @@
// --------------------------------------------------------------------------
// Private Variables
// --------------------------------------------------------------------------
static bool eeprom_initialised = false;
static bool eeprom_initialized = false;
// --------------------------------------------------------------------------
// Function prototypes
// --------------------------------------------------------------------------
@@ -82,17 +82,17 @@ static bool eeprom_initialised = false;
void eeprom_init() {
if (!eeprom_initialised) {
if (!eeprom_initialized) {
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
/* EEPROM Init */
if (EE_Initialise() != EE_OK)
if (EE_Initialize() != EE_OK)
for (;;) HAL_Delay(1); // Spin forever until watchdog reset
HAL_FLASH_Lock();
eeprom_initialised = true;
eeprom_initialized = true;
}
}
+6 -9
View File
@@ -43,8 +43,8 @@
#include <USBSerial.h>
#endif
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio_STM32F4.h"
#include "watchdog_STM32F4.h"
@@ -124,6 +124,8 @@
#define ISRS_ENABLED() (!__get_PRIMASK())
#define ENABLE_ISRS() __enable_irq()
#define DISABLE_ISRS() __disable_irq()
#define cli() __disable_irq()
#define sei() __enable_irq()
// On AVR this is in math.h?
#define square(x) ((x)*(x))
@@ -163,12 +165,6 @@ extern uint16_t HAL_adc_result;
// Public functions
// --------------------------------------------------------------------------
// Disable interrupts
#define cli() do { DISABLE_TEMPERATURE_INTERRUPT(); DISABLE_STEPPER_DRIVER_INTERRUPT(); } while(0)
// Enable interrupts
#define sei() do { ENABLE_TEMPERATURE_INTERRUPT(); ENABLE_STEPPER_DRIVER_INTERRUPT(); } while(0)
// Memory related
#define __bss_end __bss_end__
@@ -209,7 +205,6 @@ void spiSend(uint32_t chan, const uint8_t* buf, size_t n);
/** Read single byte from specified SPI channel */
uint8_t spiRec(uint32_t chan);
// EEPROM
/**
@@ -253,4 +248,6 @@ void HAL_enable_AdcFreerun(void);
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
#define JTAG_DISABLE() afio_cfg_debug_ports(AFIO_DEBUG_NONE)
#endif // _HAL_STM32F4_H
@@ -37,7 +37,7 @@
// --------------------------------------------------------------------------
#include "HAL.h"
#include "../HAL_SPI.h"
#include "../shared/HAL_SPI.h"
#include "pins_arduino.h"
#include "spi_pins.h"
#include "../../core/macros.h"
@@ -69,11 +69,11 @@ stm32f4_timer_t TimerHandle[NUM_HARDWARE_TIMERS];
// Public functions
// --------------------------------------------------------------------------
bool timers_initialised[NUM_HARDWARE_TIMERS] = {false};
bool timers_initialized[NUM_HARDWARE_TIMERS] = {false};
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
if (!timers_initialised[timer_num]) {
if (!timers_initialized[timer_num]) {
constexpr uint32_t step_prescaler = STEPPER_TIMER_PRESCALE - 1,
temp_prescaler = TEMP_TIMER_PRESCALE - 1;
switch (timer_num) {
@@ -111,7 +111,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
HAL_NVIC_SetPriority(TEMP_TIMER_IRQ_ID, 2, 0);
break;
}
timers_initialised[timer_num] = true;
timers_initialized[timer_num] = true;
}
#ifdef STM32GENERIC
@@ -120,12 +120,6 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
return __HAL_TIM_GET_AUTORELOAD(&TimerHandle[timer_num].handle);
}
FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp)
HAL_timer_set_compare(timer_num, mincmp);
}
#ifdef STM32GENERIC
FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
if (__HAL_TIM_GET_FLAG(&TimerHandle[timer_num].handle, TIM_FLAG_UPDATE) == SET)
@@ -54,6 +54,12 @@ void setup_endstop_interrupts(void) {
#if HAS_Z2_MIN
attachInterrupt(Z2_MIN_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(Z3_MAX_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(Z3_MIN_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(Z_MIN_PROBE_PIN, endstop_ISR, CHANGE);
#endif
@@ -0,0 +1,70 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#if defined(STM32F4) || defined(STM32F4xx)
#include "../shared/persistent_store_api.h"
#include "../../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS)
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
// EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v);
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing) {
do {
uint8_t c = eeprom_read_byte((unsigned char*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
size_t PersistentStore::capacity() { return E2END + 1; }
#endif // EEPROM_SETTINGS
#endif // STM32F4 || STM32F4xx
@@ -78,7 +78,7 @@ static uint16_t EE_VerifyPageFullyErased(uint32_t Address);
* @retval - Flash error code: on write Flash error
* - FLASH_COMPLETE: on success
*/
uint16_t EE_Initialise(void) {
uint16_t EE_Initialize(void) {
uint16_t PageStatus0 = 6, PageStatus1 = 6;
uint16_t VarIdx = 0;
uint16_t EepromStatus = 0, ReadStatus = 0;
@@ -109,7 +109,7 @@
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
uint16_t EE_Initialise(void);
uint16_t EE_Initialize(void);
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);
@@ -57,7 +57,7 @@
// --------------------------------------------------------------------------
// Private Variables
// --------------------------------------------------------------------------
static bool eeprom_initialised = false;
static bool eeprom_initialized = false;
// --------------------------------------------------------------------------
// Function prototypes
// --------------------------------------------------------------------------
@@ -80,17 +80,17 @@ static bool eeprom_initialised = false;
void eeprom_init() {
if (!eeprom_initialised) {
if (!eeprom_initialized) {
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
/* EEPROM Init */
if (EE_Initialise() != EE_OK)
if (EE_Initialize() != EE_OK)
for (;;) HAL_Delay(1); // Spin forever until watchdog reset
HAL_FLASH_Lock();
eeprom_initialised = true;
eeprom_initialized = true;
}
}
+4 -6
View File
@@ -39,8 +39,8 @@
#include "Arduino.h"
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio_STM32F7.h"
#include "watchdog_STM32F7.h"
@@ -114,6 +114,8 @@
#define ISRS_ENABLED() (!__get_PRIMASK())
#define ENABLE_ISRS() __enable_irq()
#define DISABLE_ISRS() __disable_irq()
#define cli() __disable_irq()
#define sei() __enable_irq()
// On AVR this is in math.h?
#define square(x) ((x)*(x))
@@ -151,11 +153,7 @@ extern uint16_t HAL_adc_result;
// Public functions
// --------------------------------------------------------------------------
// Disable interrupts
#define cli() do { DISABLE_TEMPERATURE_INTERRUPT(); DISABLE_STEPPER_DRIVER_INTERRUPT(); } while(0)
// Enable interrupts
#define sei() do { ENABLE_TEMPERATURE_INTERRUPT(); ENABLE_STEPPER_DRIVER_INTERRUPT(); } while(0)
// Memory related
#define __bss_end __bss_end__
@@ -37,11 +37,11 @@
// --------------------------------------------------------------------------
#include "HAL.h"
#include "../HAL_SPI.h"
#include "../shared/HAL_SPI.h"
#include "pins_arduino.h"
#include "spi_pins.h"
#include "../../core/macros.h"
#include <SPI.h>
// --------------------------------------------------------------------------
// Public Variables
@@ -69,11 +69,11 @@ tTimerConfig timerConfig[NUM_HARDWARE_TIMERS];
// --------------------------------------------------------------------------
bool timers_initialised[NUM_HARDWARE_TIMERS] = {false};
bool timers_initialized[NUM_HARDWARE_TIMERS] = {false};
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
if (!timers_initialised[timer_num]) {
if (!timers_initialized[timer_num]) {
switch (timer_num) {
case STEP_TIMER_NUM:
//STEPPER TIMER TIM5 //use a 32bit timer
@@ -100,7 +100,7 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
HAL_NVIC_SetPriority(timerConfig[1].IRQ_Id, 2, 0);
break;
}
timers_initialised[timer_num] = true;
timers_initialized[timer_num] = true;
}
timerConfig[timer_num].timerdef.Init.Period = (((HAL_TIMER_RATE) / timerConfig[timer_num].timerdef.Init.Prescaler) / frequency) - 1;
@@ -142,15 +142,15 @@ uint32_t HAL_timer_get_count(const uint8_t timer_num) {
return __HAL_TIM_GetCounter(&timerConfig[timer_num].timerdef);
}
void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
}
void HAL_timer_isr_prologue(const uint8_t timer_num) {
if (__HAL_TIM_GET_FLAG(&timerConfig[timer_num].timerdef, TIM_FLAG_UPDATE) == SET) {
__HAL_TIM_CLEAR_FLAG(&timerConfig[timer_num].timerdef, TIM_FLAG_UPDATE);
}
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
const uint32_t IRQ_Id = uint32_t(timerConfig[timer_num].IRQ_Id);
return NVIC->ISER[IRQ_Id >> 5] & _BV32(IRQ_Id & 0x1F);
}
#endif // STM32F7
@@ -61,6 +61,8 @@
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(STEP_TIMER_NUM)
#define TEMP_ISR_ENABLED() HAL_timer_interrupt_enabled(TEMP_TIMER_NUM)
// TODO change this
@@ -92,12 +94,11 @@ typedef struct {
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
void HAL_timer_set_compare(const uint8_t timer_num, const uint32_t compare);
hal_timer_t HAL_timer_get_compare(const uint8_t timer_num);
uint32_t HAL_timer_get_count(const uint8_t timer_num);
void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks);
void HAL_timer_isr_prologue(const uint8_t timer_num);
#define HAL_timer_isr_epilogue(TIMER_NUM)
+2
View File
@@ -53,6 +53,8 @@
#error "SPINDLE_LASER_PWM_PIN is used by E3_AUTO_FAN_PIN."
#elif PIN_EXISTS(E4_AUTO_FAN) && SPINDLE_LASER_PWM_PIN == E4_AUTO_FAN_PIN
#error "SPINDLE_LASER_PWM_PIN is used by E4_AUTO_FAN_PIN."
#elif PIN_EXISTS(E5_AUTO_FAN) && SPINDLE_LASER_PWM_PIN == E5_AUTO_FAN_PIN
#error "SPINDLE_LASER_PWM_PIN is used by E5_AUTO_FAN_PIN."
#elif PIN_EXISTS(FAN) && SPINDLE_LASER_PWM_PIN == FAN_PIN
#error "SPINDLE_LASER_PWM_PIN is used FAN_PIN."
#elif PIN_EXISTS(FAN1) && SPINDLE_LASER_PWM_PIN == FAN1_PIN
+90 -90
View File
@@ -33,7 +33,7 @@
#include <SPI.h>
#include "TMC2660.h"
#include "../../HAL/HAL_STM32F7/HAL_STM32F7.h"
#include "../../HAL/HAL_STM32F7/HAL.h"
#include "../../core/serial.h"
#include "../../inc/MarlinConfig.h"
#include "../../Marlin.h"
@@ -87,7 +87,7 @@
#define SE_CURRENT_STEP_WIDTH_PATTERN 0x60ul
#define SE_MIN_PATTERN 0xFul
//definitions for stall guard2 current register
//definitions for StallGuard2 current register
#define STALL_GUARD_FILTER_ENABLED 0x10000ul
#define STALL_GUARD_TRESHHOLD_VALUE_PATTERN 0x17F00ul
#define CURRENT_SCALING_PATTERN 0x1Ful
@@ -118,7 +118,7 @@ SPIClass SPI_6(SPI6, SPI6_MOSI_PIN, SPI6_MISO_PIN, SPI6_SCK_PIN);
//#define TMC_DEBUG1
unsigned char current_scaling = 0;
uint8_t current_scaling = 0;
/**
* Constructor
@@ -127,7 +127,7 @@ unsigned char current_scaling = 0;
* dir_pin - the pin where the direction pin is connected
* step_pin - the pin where the step pin is connected
*/
TMC26XStepper::TMC26XStepper(int number_of_steps, int cs_pin, int dir_pin, int step_pin, unsigned int current, unsigned int resistor) {
TMC26XStepper::TMC26XStepper(int16_t number_of_steps, int16_t cs_pin, int16_t dir_pin, int16_t step_pin, uint16_t current, uint16_t resistor) {
// We are not started yet
started = false;
@@ -155,7 +155,7 @@ TMC26XStepper::TMC26XStepper(int number_of_steps, int cs_pin, int dir_pin, int s
microsteps = _BV(INITIAL_MICROSTEPPING);
chopper_config_register = CHOPPER_CONFIG_REGISTER;
cool_step_register_value = COOL_STEP_REGISTER;
stall_guard2_current_register_value = STALL_GUARD2_LOAD_MEASURE_REGISTER;
stallguard2_current_register_value = STALL_GUARD2_LOAD_MEASURE_REGISTER;
driver_configuration_register_value = DRIVER_CONFIG_REGISTER | READ_STALL_GUARD_READING;
// Set the current
@@ -202,7 +202,7 @@ void TMC26XStepper::start() {
send262(driver_control_register_value);
send262(chopper_config_register);
send262(cool_step_register_value);
send262(stall_guard2_current_register_value);
send262(stallguard2_current_register_value);
send262(driver_configuration_register_value);
//save that we are in running mode
@@ -218,9 +218,9 @@ void TMC26XStepper::un_start() { started = false; }
/**
* Sets the speed in revs per minute
*/
void TMC26XStepper::setSpeed(unsigned int whatSpeed) {
void TMC26XStepper::setSpeed(uint16_t whatSpeed) {
this->speed = whatSpeed;
this->step_delay = 60UL * sq(1000UL) / ((unsigned long)this->number_of_steps * (unsigned long)whatSpeed * (unsigned long)this->microsteps);
this->step_delay = 60UL * sq(1000UL) / ((uint32_t)this->number_of_steps * (uint32_t)whatSpeed * (uint32_t)this->microsteps);
#ifdef TMC_DEBUG0 // crashes
//SERIAL_PRINTF("Step delay in micros: ");
SERIAL_ECHOPAIR("\nStep delay in micros: ", this->step_delay);
@@ -229,13 +229,13 @@ void TMC26XStepper::setSpeed(unsigned int whatSpeed) {
this->next_step_time = this->last_step_time + this->step_delay;
}
unsigned int TMC26XStepper::getSpeed(void) { return this->speed; }
uint16_t TMC26XStepper::getSpeed(void) { return this->speed; }
/**
* Moves the motor steps_to_move steps.
* Negative indicates the reverse direction.
*/
char TMC26XStepper::step(int steps_to_move) {
char TMC26XStepper::step(int16_t steps_to_move) {
if (this->steps_left == 0) {
this->steps_left = ABS(steps_to_move); // how many steps to take
@@ -252,7 +252,7 @@ char TMC26XStepper::step(int steps_to_move) {
char TMC26XStepper::move(void) {
// decrement the number of steps, moving one step each time:
if (this->steps_left > 0) {
unsigned long time = micros();
uint32_t time = micros();
// move only if the appropriate delay has passed:
// rem if (time >= this->next_step_time) {
@@ -282,7 +282,7 @@ char TMC26XStepper::move(void) {
char TMC26XStepper::isMoving(void) { return this->steps_left > 0; }
unsigned int TMC26XStepper::getStepsLeft(void) { return this->steps_left; }
uint16_t TMC26XStepper::getStepsLeft(void) { return this->steps_left; }
char TMC26XStepper::stop(void) {
//note to self if the motor is currently moving
@@ -294,8 +294,8 @@ char TMC26XStepper::stop(void) {
return state;
}
void TMC26XStepper::setCurrent(unsigned int current) {
unsigned char current_scaling = 0;
void TMC26XStepper::setCurrent(uint16_t current) {
uint8_t current_scaling = 0;
//calculate the current scaling from the max current setting (in mA)
float mASetting = (float)current,
resistor_value = (float)this->resistor;
@@ -327,49 +327,49 @@ void TMC26XStepper::setCurrent(unsigned int current) {
NOMORE(current_scaling, 31);
// delete the old value
stall_guard2_current_register_value &= ~(CURRENT_SCALING_PATTERN);
stallguard2_current_register_value &= ~(CURRENT_SCALING_PATTERN);
// set the new current scaling
stall_guard2_current_register_value |= current_scaling;
stallguard2_current_register_value |= current_scaling;
// if started we directly send it to the motor
if (started) {
send262(driver_configuration_register_value);
send262(stall_guard2_current_register_value);
send262(stallguard2_current_register_value);
}
}
unsigned int TMC26XStepper::getCurrent(void) {
uint16_t TMC26XStepper::getCurrent(void) {
// Calculate the current according to the datasheet to be on the safe side.
// This is not the fastest but the most accurate and illustrative way.
float result = (float)(stall_guard2_current_register_value & CURRENT_SCALING_PATTERN),
float result = (float)(stallguard2_current_register_value & CURRENT_SCALING_PATTERN),
resistor_value = (float)this->resistor,
voltage = (driver_configuration_register_value & VSENSE) ? 0.165 : 0.31;
result = (result + 1.0) / 32.0 * voltage / resistor_value * sq(1000.0);
return (unsigned int)result;
return (uint16_t)result;
}
void TMC26XStepper::setStallGuardThreshold(char stall_guard_threshold, char stall_guard_filter_enabled) {
void TMC26XStepper::setStallGuardThreshold(char stallguard_threshold, char stallguard_filter_enabled) {
// We just have 5 bits
LIMIT(stall_guard_threshold, -64, 63);
LIMIT(stallguard_threshold, -64, 63);
// Add trim down to 7 bits
stall_guard_threshold &= 0x7F;
// Delete old stall guard settings
stall_guard2_current_register_value &= ~(STALL_GUARD_CONFIG_PATTERN);
if (stall_guard_filter_enabled)
stall_guard2_current_register_value |= STALL_GUARD_FILTER_ENABLED;
stallguard_threshold &= 0x7F;
// Delete old StallGuard settings
stallguard2_current_register_value &= ~(STALL_GUARD_CONFIG_PATTERN);
if (stallguard_filter_enabled)
stallguard2_current_register_value |= STALL_GUARD_FILTER_ENABLED;
// Set the new stall guard threshold
stall_guard2_current_register_value |= (((unsigned long)stall_guard_threshold << 8) & STALL_GUARD_CONFIG_PATTERN);
// Set the new StallGuard threshold
stallguard2_current_register_value |= (((uint32_t)stallguard_threshold << 8) & STALL_GUARD_CONFIG_PATTERN);
// If started we directly send it to the motor
if (started) send262(stall_guard2_current_register_value);
if (started) send262(stallguard2_current_register_value);
}
char TMC26XStepper::getStallGuardThreshold(void) {
unsigned long stall_guard_threshold = stall_guard2_current_register_value & STALL_GUARD_VALUE_PATTERN;
uint32_t stallguard_threshold = stallguard2_current_register_value & STALL_GUARD_VALUE_PATTERN;
//shift it down to bit 0
stall_guard_threshold >>= 8;
//convert the value to an int to correctly handle the negative numbers
char result = stall_guard_threshold;
stallguard_threshold >>= 8;
//convert the value to an int16_t to correctly handle the negative numbers
char result = stallguard_threshold;
//check if it is negative and fill it up with leading 1 for proper negative number representation
//rem if (result & _BV(6)) {
@@ -378,7 +378,7 @@ char TMC26XStepper::getStallGuardThreshold(void) {
}
char TMC26XStepper::getStallGuardFilter(void) {
if (stall_guard2_current_register_value & STALL_GUARD_FILTER_ENABLED)
if (stallguard2_current_register_value & STALL_GUARD_FILTER_ENABLED)
return -1;
return 0;
}
@@ -389,7 +389,7 @@ char TMC26XStepper::getStallGuardFilter(void) {
* any value in between will be mapped to the next smaller value
* 0 and 1 set the motor in full step mode
*/
void TMC26XStepper::setMicrosteps(int number_of_steps) {
void TMC26XStepper::setMicrosteps(int16_t number_of_steps) {
long setting_pattern;
//poor mans log
if (number_of_steps >= 256) {
@@ -448,7 +448,7 @@ void TMC26XStepper::setMicrosteps(int number_of_steps) {
/**
* returns the effective number of microsteps at the moment
*/
int TMC26XStepper::getMicrosteps(void) { return microsteps }
int16_t TMC26XStepper::getMicrosteps(void) { return microsteps; }
/**
* constant_off_time: The off time setting controls the minimum chopper frequency.
@@ -473,7 +473,7 @@ int TMC26XStepper::getMicrosteps(void) { return microsteps }
* 1: enable comparator termination of fast decay cycle
* 0: end by time only
*/
void TMC26XStepper::setConstantOffTimeChopper(char constant_off_time, char blank_time, char fast_decay_time_setting, char sine_wave_offset, unsigned char use_current_comparator) {
void TMC26XStepper::setConstantOffTimeChopper(char constant_off_time, char blank_time, char fast_decay_time_setting, char sine_wave_offset, uint8_t use_current_comparator) {
// Perform some sanity checks
LIMIT(constant_off_time, 2, 15);
@@ -497,16 +497,16 @@ void TMC26XStepper::setConstantOffTimeChopper(char constant_off_time, char blank
// Set the constant off pattern
chopper_config_register |= CHOPPER_MODE_T_OFF_FAST_DECAY;
// Set the blank timing value
chopper_config_register |= ((unsigned long)blank_value) << BLANK_TIMING_SHIFT;
chopper_config_register |= ((uint32_t)blank_value) << BLANK_TIMING_SHIFT;
// Setting the constant off time
chopper_config_register |= constant_off_time;
// Set the fast decay time
// Set msb
chopper_config_register |= (((unsigned long)(fast_decay_time_setting & 0x8)) << HYSTERESIS_DECREMENT_SHIFT);
chopper_config_register |= (((uint32_t)(fast_decay_time_setting & 0x8)) << HYSTERESIS_DECREMENT_SHIFT);
// Other bits
chopper_config_register |= (((unsigned long)(fast_decay_time_setting & 0x7)) << HYSTERESIS_START_VALUE_SHIFT);
chopper_config_register |= (((uint32_t)(fast_decay_time_setting & 0x7)) << HYSTERESIS_START_VALUE_SHIFT);
// Set the sine wave offset
chopper_config_register |= (unsigned long)sine_wave_offset << HYSTERESIS_LOW_SHIFT;
chopper_config_register |= (uint32_t)sine_wave_offset << HYSTERESIS_LOW_SHIFT;
// Using the current comparator?
if (!use_current_comparator)
chopper_config_register |= _BV(12);
@@ -564,15 +564,15 @@ void TMC26XStepper::setSpreadCycleChopper(char constant_off_time, char blank_tim
chopper_config_register &= ~(CHOPPER_MODE_T_OFF_FAST_DECAY | BLANK_TIMING_PATTERN | HYSTERESIS_DECREMENT_PATTERN | HYSTERESIS_LOW_VALUE_PATTERN | HYSTERESIS_START_VALUE_PATTERN | T_OFF_TIMING_PATERN);
//set the blank timing value
chopper_config_register |= ((unsigned long)blank_value) << BLANK_TIMING_SHIFT;
chopper_config_register |= ((uint32_t)blank_value) << BLANK_TIMING_SHIFT;
//setting the constant off time
chopper_config_register |= constant_off_time;
//set the hysteresis_start
chopper_config_register |= ((unsigned long)hysteresis_start) << HYSTERESIS_START_VALUE_SHIFT;
chopper_config_register |= ((uint32_t)hysteresis_start) << HYSTERESIS_START_VALUE_SHIFT;
//set the hysteresis end
chopper_config_register |= ((unsigned long)hysteresis_end) << HYSTERESIS_LOW_SHIFT;
chopper_config_register |= ((uint32_t)hysteresis_end) << HYSTERESIS_LOW_SHIFT;
//set the hystereis decrement
chopper_config_register |= ((unsigned long)blank_value) << BLANK_TIMING_SHIFT;
chopper_config_register |= ((uint32_t)blank_value) << BLANK_TIMING_SHIFT;
//if started we directly send it to the motor
if (started) {
//rem send262(driver_control_register_value);
@@ -605,12 +605,12 @@ void TMC26XStepper::setRandomOffTime(char value) {
}
void TMC26XStepper::setCoolStepConfiguration(
unsigned int lower_SG_threshold,
unsigned int SG_hysteresis,
unsigned char current_decrement_step_size,
unsigned char current_increment_step_size,
unsigned char lower_current_limit)
{
uint16_t lower_SG_threshold,
uint16_t SG_hysteresis,
uint8_t current_decrement_step_size,
uint8_t current_increment_step_size,
uint8_t lower_current_limit
) {
// Sanitize the input values
NOMORE(lower_SG_threshold, 480);
// Divide by 32
@@ -628,11 +628,11 @@ void TMC26XStepper::setCoolStepConfiguration(
if (!this->cool_step_enabled) lower_SG_threshold = 0;
// The good news is that we can start with a complete new cool step register value
// And simply set the values in the register
cool_step_register_value = ((unsigned long)lower_SG_threshold)
| (((unsigned long)SG_hysteresis) << 8)
| (((unsigned long)current_decrement_step_size) << 5)
| (((unsigned long)current_increment_step_size) << 13)
| (((unsigned long)lower_current_limit) << 15)
cool_step_register_value = ((uint32_t)lower_SG_threshold)
| (((uint32_t)SG_hysteresis) << 8)
| (((uint32_t)current_decrement_step_size) << 5)
| (((uint32_t)current_increment_step_size) << 13)
| (((uint32_t)lower_current_limit) << 15)
| COOL_STEP_REGISTER; // Register signature
//SERIAL_PRINTFln(cool_step_register_value,HEX);
@@ -653,25 +653,25 @@ void TMC26XStepper::setCoolStepEnabled(boolean enabled) {
boolean TMC26XStepper::isCoolStepEnabled(void) { return this->cool_step_enabled; }
unsigned int TMC26XStepper::getCoolStepLowerSgThreshold() {
uint16_t TMC26XStepper::getCoolStepLowerSgThreshold() {
// We return our internally stored value - in order to provide the correct setting even if cool step is not enabled
return this->cool_step_lower_threshold<<5;
}
unsigned int TMC26XStepper::getCoolStepUpperSgThreshold() {
return (unsigned char)((cool_step_register_value & SE_MAX_PATTERN) >> 8) << 5;
uint16_t TMC26XStepper::getCoolStepUpperSgThreshold() {
return (uint8_t)((cool_step_register_value & SE_MAX_PATTERN) >> 8) << 5;
}
unsigned char TMC26XStepper::getCoolStepCurrentIncrementSize() {
return (unsigned char)((cool_step_register_value & CURRENT_DOWN_STEP_SPEED_PATTERN) >> 13);
uint8_t TMC26XStepper::getCoolStepCurrentIncrementSize() {
return (uint8_t)((cool_step_register_value & CURRENT_DOWN_STEP_SPEED_PATTERN) >> 13);
}
unsigned char TMC26XStepper::getCoolStepNumberOfSGReadings() {
return (unsigned char)((cool_step_register_value & SE_CURRENT_STEP_WIDTH_PATTERN) >> 5);
uint8_t TMC26XStepper::getCoolStepNumberOfSGReadings() {
return (uint8_t)((cool_step_register_value & SE_CURRENT_STEP_WIDTH_PATTERN) >> 5);
}
unsigned char TMC26XStepper::getCoolStepLowerCurrentLimit() {
return (unsigned char)((cool_step_register_value & MINIMUM_CURRENT_FOURTH) >> 15);
uint8_t TMC26XStepper::getCoolStepLowerCurrentLimit() {
return (uint8_t)((cool_step_register_value & MINIMUM_CURRENT_FOURTH) >> 15);
}
void TMC26XStepper::setEnabled(boolean enabled) {
@@ -693,7 +693,7 @@ boolean TMC26XStepper::isEnabled() { return !!(chopper_config_register & T_OFF_P
*
*/
void TMC26XStepper::readStatus(char read_value) {
unsigned long old_driver_configuration_register_value = driver_configuration_register_value;
uint32_t old_driver_configuration_register_value = driver_configuration_register_value;
//reset the readout configuration
driver_configuration_register_value &= ~(READ_SELECTION_PATTERN);
//this now equals TMC26X_READOUT_POSITION - so we just have to check the other two options
@@ -712,42 +712,42 @@ void TMC26XStepper::readStatus(char read_value) {
send262(driver_configuration_register_value);
}
int TMC26XStepper::getMotorPosition(void) {
int16_t TMC26XStepper::getMotorPosition(void) {
//we read it out even if we are not started yet - perhaps it is useful information for somebody
readStatus(TMC26X_READOUT_POSITION);
return getReadoutValue();
}
//reads the stall guard setting from last status
//returns -1 if stallguard information is not present
int TMC26XStepper::getCurrentStallGuardReading(void) {
//if we don't yet started there cannot be a stall guard value
//reads the StallGuard setting from last status
//returns -1 if StallGuard information is not present
int16_t TMC26XStepper::getCurrentStallGuardReading(void) {
//if we don't yet started there cannot be a StallGuard value
if (!started) return -1;
//not time optimal, but solution optiomal:
//first read out the stall guard value
//first read out the StallGuard value
readStatus(TMC26X_READOUT_STALLGUARD);
return getReadoutValue();
}
unsigned char TMC26XStepper::getCurrentCSReading(void) {
//if we don't yet started there cannot be a stall guard value
uint8_t TMC26XStepper::getCurrentCSReading(void) {
//if we don't yet started there cannot be a StallGuard value
if (!started) return 0;
//not time optimal, but solution optiomal:
//first read out the stall guard value
//first read out the StallGuard value
readStatus(TMC26X_READOUT_CURRENT);
return (getReadoutValue() & 0x1F);
}
unsigned int TMC26XStepper::getCurrentCurrent(void) {
uint16_t TMC26XStepper::getCurrentCurrent(void) {
float result = (float)getCurrentCSReading(),
resistor_value = (float)this->resistor,
voltage = (driver_configuration_register_value & VSENSE)? 0.165 : 0.31;
result = (result + 1.0) / 32.0 * voltage / resistor_value * sq(1000.0);
return (unsigned int)result;
return (uint16_t)result;
}
/**
* Return true if the stallguard threshold has been reached
* Return true if the StallGuard threshold has been reached
*/
boolean TMC26XStepper::isStallGuardOverThreshold(void) {
if (!this->started) return false;
@@ -808,13 +808,13 @@ boolean TMC26XStepper::isStallGuardReached(void) {
return (driver_status_result & STATUS_STALL_GUARD_STATUS);
}
//reads the stall guard setting from last status
//returns -1 if stallguard inforamtion is not present
int TMC26XStepper::getReadoutValue(void) {
//reads the StallGuard setting from last status
//returns -1 if StallGuard information is not present
int16_t TMC26XStepper::getReadoutValue(void) {
return (int)(driver_status_result >> 10);
}
int TMC26XStepper::getResistor() { return this->resistor; }
int16_t TMC26XStepper::getResistor() { return this->resistor; }
boolean TMC26XStepper::isCurrentScalingHalfed() {
return !!(this->driver_configuration_register_value & VSENSE);
@@ -822,7 +822,7 @@ boolean TMC26XStepper::isCurrentScalingHalfed() {
/**
* version() returns the version of the library:
*/
int TMC26XStepper::version(void) { return 1; }
int16_t TMC26XStepper::version(void) { return 1; }
void TMC26XStepper::debugLastStatus() {
#ifdef TMC_DEBUG1
@@ -850,8 +850,8 @@ void TMC26XStepper::debugLastStatus() {
if (this->isStandStill())
SERIAL_ECHOLNPGM("\n INFO: Motor is standing still.");
unsigned long readout_config = driver_configuration_register_value & READ_SELECTION_PATTERN;
const int value = getReadoutValue();
uint32_t readout_config = driver_configuration_register_value & READ_SELECTION_PATTERN;
const int16_t value = getReadoutValue();
if (readout_config == READ_MICROSTEP_POSTION) {
//SERIAL_PRINTF("Microstep postion phase A: ");
SERIAL_ECHOPAIR("\n Microstep postion phase A: ", value);
@@ -861,7 +861,7 @@ void TMC26XStepper::debugLastStatus() {
SERIAL_ECHOPAIR("\n Stall Guard value:", value);
}
else if (readout_config == READ_STALL_GUARD_AND_COOL_STEP) {
int stallGuard = value & 0xF, current = value & 0x1F0;
int16_t stallGuard = value & 0xF, current = value & 0x1F0;
//SERIAL_PRINTF("Approx Stall Guard: ");
SERIAL_ECHOPAIR("\n Approx Stall Guard: ", stallGuard);
//SERIAL_PRINTF("Current level");
@@ -875,11 +875,11 @@ void TMC26XStepper::debugLastStatus() {
* send register settings to the stepper driver via SPI
* returns the current status
*/
inline void TMC26XStepper::send262(unsigned long datagram) {
unsigned long i_datagram;
inline void TMC26XStepper::send262(uint32_t datagram) {
uint32_t i_datagram;
//preserver the previous spi mode
//unsigned char oldMode = SPCR & SPI_MODE_MASK;
//uint8_t oldMode = SPCR & SPI_MODE_MASK;
//if the mode is not correct set it to mode 3
//if (oldMode != SPI_MODE3) {
+47 -49
View File
@@ -83,7 +83,7 @@
* \code
* TMC26XStepper stepper = TMC26XStepper(200,1,2,3,500);
* \endcode
* see TMC26XStepper(int number_of_steps, int cs_pin, int dir_pin, int step_pin, unsigned int rms_current)
* see TMC26XStepper(int16_t number_of_steps, int16_t cs_pin, int16_t dir_pin, int16_t step_pin, uint16_t rms_current)
*
* Keep in mind that you need to start the driver with start() in order to get the TMC26X configured.
*
@@ -122,7 +122,7 @@ class TMC26XStepper {
* You can select a different stepping with setMicrosteps() to aa different value.
* \sa start(), setMicrosteps()
*/
TMC26XStepper(int number_of_steps, int cs_pin, int dir_pin, int step_pin, unsigned int current, unsigned int resistor=100); //resistor=150
TMC26XStepper(int16_t number_of_steps, int16_t cs_pin, int16_t dir_pin, int16_t step_pin, uint16_t current, uint16_t resistor=100); //resistor=150
/*!
* \brief configures and starts the TMC26X stepper driver. Before you called this function the stepper driver is in nonfunctional mode.
@@ -150,13 +150,13 @@ class TMC26XStepper {
* \brief Sets the rotation speed in revolutions per minute.
* \param whatSpeed the desired speed in rotations per minute.
*/
void setSpeed(unsigned int whatSpeed);
void setSpeed(uint16_t whatSpeed);
/*!
* \brief reads out the currently selected speed in revolutions per minute.
* \sa setSpeed()
*/
unsigned int getSpeed(void);
uint16_t getSpeed(void);
/*!
* \brief Set the number of microsteps in 2^i values (rounded) up to 256
@@ -166,7 +166,7 @@ class TMC26XStepper {
* If you give any other value it will be rounded to the next smaller number (3 would give a microstepping of 2).
* You can always check the current microstepping with getMicrosteps().
*/
void setMicrosteps(int number_of_steps);
void setMicrosteps(int16_t number_of_steps);
/*!
* \brief returns the effective current number of microsteps selected.
@@ -176,7 +176,7 @@ class TMC26XStepper {
*
* \sa setMicrosteps()
*/
int getMicrosteps(void);
int16_t getMicrosteps(void);
/*!
* \brief Initiate a movement for the given number of steps. Positive numbers move in one, negative numbers in the other direction.
@@ -193,7 +193,7 @@ class TMC26XStepper {
* You can always verify with isMoving() or even use stop() to stop the motor before giving it new step directions.
* \sa isMoving(), getStepsLeft(), stop()
*/
char step(int number_of_steps);
char step(int16_t number_of_steps);
/*!
* \brief Central movement method, must be called as often as possible in the lopp function and is very fast.
@@ -228,7 +228,7 @@ class TMC26XStepper {
* \brief Get the number of steps left in the current movement.
* \return The number of steps left in the movement. This number is always positive.
*/
unsigned int getStepsLeft(void);
uint16_t getStepsLeft(void);
/*!
* \brief Stops the motor regardless if it moves or not.
@@ -262,7 +262,7 @@ class TMC26XStepper {
* \sa setSpreadCycleChoper() for other alternatives.
* \sa setRandomOffTime() for spreading the noise over a wider spectrum
*/
void setConstantOffTimeChopper(char constant_off_time, char blank_time, char fast_decay_time_setting, char sine_wave_offset, unsigned char use_current_comparator);
void setConstantOffTimeChopper(char constant_off_time, char blank_time, char fast_decay_time_setting, char sine_wave_offset, uint8_t use_current_comparator);
/*!
* \brief Sets and configures with spread cycle chopper.
@@ -310,7 +310,7 @@ class TMC26XStepper {
* \param current the maximum motor current in mA
* \sa getCurrent(), getCurrentCurrent()
*/
void setCurrent(unsigned int current);
void setCurrent(uint16_t current);
/*!
* \brief readout the motor maximum current in mA (1000 is an Amp)
@@ -318,12 +318,12 @@ class TMC26XStepper {
* \return the maximum motor current in milli amps
* \sa getCurrentCurrent()
*/
unsigned int getCurrent(void);
uint16_t getCurrent(void);
/*!
* \brief set the StallGuard threshold in order to get sensible StallGuard readings.
* \param stall_guard_threshold -64 … 63 the StallGuard threshold
* \param stall_guard_filter_enabled 0 if the filter is disabled, -1 if it is enabled
* \param stallguard_threshold -64 … 63 the StallGuard threshold
* \param stallguard_filter_enabled 0 if the filter is disabled, -1 if it is enabled
*
* The StallGuard threshold is used to optimize the StallGuard reading to sensible values. It should be at 0 at
* the maximum allowable load on the otor (but not before). = is a good starting point (and the default)
@@ -335,7 +335,7 @@ class TMC26XStepper {
*
* \sa getCurrentStallGuardReading() to read out the current value.
*/
void setStallGuardThreshold(char stall_guard_threshold, char stall_guard_filter_enabled);
void setStallGuardThreshold(char stallguard_threshold, char stallguard_filter_enabled);
/*!
* \brief reads out the StallGuard threshold
@@ -366,8 +366,8 @@ class TMC26XStepper {
* (1/2 or 1/4th otf the configured current).
* \sa COOL_STEP_HALF_CS_LIMIT, COOL_STEP_QUARTER_CS_LIMIT
*/
void setCoolStepConfiguration(unsigned int lower_SG_threshold, unsigned int SG_hysteresis, unsigned char current_decrement_step_size,
unsigned char current_increment_step_size, unsigned char lower_current_limit);
void setCoolStepConfiguration(uint16_t lower_SG_threshold, uint16_t SG_hysteresis, uint8_t current_decrement_step_size,
uint8_t current_increment_step_size, uint8_t lower_current_limit);
/*!
* \brief enables or disables the CoolStep smart energy operation feature. It must be configured before enabling it.
@@ -387,32 +387,32 @@ class TMC26XStepper {
* \brief returns the lower StallGuard threshold for the CoolStep operation
* \sa setCoolStepConfiguration()
*/
unsigned int getCoolStepLowerSgThreshold();
uint16_t getCoolStepLowerSgThreshold();
/*!
* \brief returns the upper StallGuard threshold for the CoolStep operation
* \sa setCoolStepConfiguration()
*/
unsigned int getCoolStepUpperSgThreshold();
uint16_t getCoolStepUpperSgThreshold();
/*!
* \brief returns the number of StallGuard readings befor CoolStep adjusts the motor current.
* \sa setCoolStepConfiguration()
*/
unsigned char getCoolStepNumberOfSGReadings();
uint8_t getCoolStepNumberOfSGReadings();
/*!
* \brief returns the increment steps for the current for the CoolStep operation
* \sa setCoolStepConfiguration()
*/
unsigned char getCoolStepCurrentIncrementSize();
uint8_t getCoolStepCurrentIncrementSize();
/*!
* \brief returns the absolut minium current for the CoolStep operation
* \sa setCoolStepConfiguration()
* \sa COOL_STEP_HALF_CS_LIMIT, COOL_STEP_QUARTER_CS_LIMIT
*/
unsigned char getCoolStepLowerCurrentLimit();
uint8_t getCoolStepLowerCurrentLimit();
/*!
* \brief Get the current microstep position for phase A
@@ -420,7 +420,7 @@ class TMC26XStepper {
*
* Keep in mind that this routine reads and writes a value via SPI - so this may take a bit time.
*/
int getMotorPosition(void);
int16_t getMotorPosition(void);
/*!
* \brief Reads the current StallGuard value.
@@ -428,14 +428,14 @@ class TMC26XStepper {
* Keep in mind that this routine reads and writes a value via SPI - so this may take a bit time.
* \sa setStallGuardThreshold() for tuning the readout to sensible ranges.
*/
int getCurrentStallGuardReading(void);
int16_t getCurrentStallGuardReading(void);
/*!
* \brief Reads the current current setting value as fraction of the maximum current
* Returns values between 0 and 31, representing 1/32 to 32/32 (=1)
* \sa setCoolStepConfiguration()
*/
unsigned char getCurrentCSReading(void);
uint8_t getCurrentCSReading(void);
/*!
@@ -451,7 +451,7 @@ class TMC26XStepper {
* may not be the fastest.
* \sa getCurrentCSReading(), getResistor(), isCurrentScalingHalfed(), getCurrent()
*/
unsigned int getCurrentCurrent(void);
uint16_t getCurrentCurrent(void);
/*!
* \brief checks if there is a StallGuard warning in the last status
@@ -552,56 +552,54 @@ class TMC26XStepper {
* \brief Returns the current sense resistor value in milliohm.
* The default value of ,15 Ohm will return 150.
*/
int getResistor();
int16_t getResistor();
/*!
* \brief Prints out all the information that can be found in the last status read out - it does not force a status readout.
* The result is printed via Serial
*/
void debugLastStatus(void);
/*!
* \brief library version
* \return the version number as int.
*/
int version(void);
int16_t version(void);
private:
unsigned int steps_left; // The steps the motor has to do to complete the movement
int direction; // Direction of rotation
unsigned long step_delay; // Delay between steps, in ms, based on speed
int number_of_steps; // Total number of steps this motor can take
unsigned int speed; // Store the current speed in order to change the speed after changing microstepping
unsigned int resistor; // Current sense resitor value in milliohm
uint16_t steps_left; // The steps the motor has to do to complete the movement
int16_t direction; // Direction of rotation
uint32_t step_delay; // Delay between steps, in ms, based on speed
int16_t number_of_steps; // Total number of steps this motor can take
uint16_t speed; // Store the current speed in order to change the speed after changing microstepping
uint16_t resistor; // Current sense resitor value in milliohm
unsigned long last_step_time; // Time stamp in ms of when the last step was taken
unsigned long next_step_time; // Time stamp in ms of when the last step was taken
uint32_t last_step_time, // Timestamp (ms) of the last step
next_step_time; // Timestamp (ms) of the next step
// Driver control register copies to easily set & modify the registers
unsigned long driver_control_register_value;
unsigned long chopper_config_register;
unsigned long cool_step_register_value;
unsigned long stall_guard2_current_register_value;
unsigned long driver_configuration_register_value;
// The driver status result
unsigned long driver_status_result;
uint32_t driver_control_register_value,
chopper_config_register,
cool_step_register_value,
stallguard2_current_register_value,
driver_configuration_register_value,
driver_status_result; // The driver status result
// Helper routione to get the top 10 bit of the readout
inline int getReadoutValue();
inline int16_t getReadoutValue();
// The pins for the stepper driver
unsigned char cs_pin;
unsigned char step_pin;
unsigned char dir_pin;
uint8_t cs_pin, step_pin, dir_pin;
// Status values
boolean started; // If the stepper has been started yet
int microsteps; // The current number of micro steps
int16_t microsteps; // The current number of micro steps
char constant_off_time; // We need to remember this value in order to enable and disable the motor
unsigned char cool_step_lower_threshold; // we need to remember the threshold to enable and disable the CoolStep feature
uint8_t cool_step_lower_threshold; // we need to remember the threshold to enable and disable the CoolStep feature
boolean cool_step_enabled; // We need to remember this to configure the coolstep if it si enabled
// SPI sender
inline void send262(unsigned long datagram);
inline void send262(uint32_t datagram);
};
#endif // _TMC26XSTEPPER_H_
@@ -56,6 +56,12 @@ void setup_endstop_interrupts(void) {
#if HAS_Z2_MIN
attachInterrupt(Z2_MIN_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(Z3_MAX_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(Z3_MIN_PIN, endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(Z_MIN_PROBE_PIN, endstop_ISR, CHANGE);
#endif
@@ -0,0 +1,70 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef STM32F7
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../shared/persistent_store_api.h"
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
// EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v);
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc) {
do {
uint8_t c = eeprom_read_byte((unsigned char*)pos);
*value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
size_t PersistentStore::capacity() { return E2END + 1; }
#endif // EEPROM_SETTINGS
#endif // STM32F7
+90
View File
@@ -0,0 +1,90 @@
/* **************************************************************************
Marlin 3D Printer Firmware
Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
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 <http://www.gnu.org/licenses/>.
****************************************************************************/
/**
* Description: HAL for Teensy32 (MK20DX256)
*/
#ifdef __MK20DX256__
#include "HAL.h"
#include "../Delay.h"
#include <Wire.h>
uint16_t HAL_adc_result;
static const uint8_t pin2sc1a[] = {
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 0, 19, 3, 31, // 0-13, we treat them as A0-A13
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 (A0-A9)
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, // 24-33
0+64, 19+64, 3+64, 31+64, // 34-37 (A10-A13)
26, 22, 23, 27, 29, 30 // 38-43: temp. sensor, VREF_OUT, A14, bandgap, VREFH, VREFL. A14 isn't connected to anything in Teensy 3.0.
};
/*
// disable interrupts
void cli(void) { noInterrupts(); }
// enable interrupts
void sei(void) { interrupts(); }
*/
void HAL_adc_init() {
analog_init();
while (ADC0_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish
NVIC_ENABLE_IRQ(IRQ_FTM1);
}
void HAL_clear_reset_source(void) { }
uint8_t HAL_get_reset_source(void) {
switch (RCM_SRS0) {
case 128: return RST_POWER_ON; break;
case 64: return RST_EXTERNAL; break;
case 32: return RST_WATCHDOG; break;
// case 8: return RST_LOSS_OF_LOCK; break;
// case 4: return RST_LOSS_OF_CLOCK; break;
// case 2: return RST_LOW_VOLTAGE; break;
}
return 0;
}
extern "C" {
extern char __bss_end;
extern char __heap_start;
extern void* __brkval;
int freeMemory() {
int free_memory;
if ((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
}
void HAL_adc_start_conversion(const uint8_t adc_pin) { ADC0_SC1A = pin2sc1a[adc_pin]; }
uint16_t HAL_adc_get_result(void) { return ADC0_RA; }
#endif // __MK20DX256__
+159
View File
@@ -0,0 +1,159 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Description: HAL for Teensy 3.5 and Teensy 3.6
*/
#pragma once
#define CPU_32_BIT
// _BV is re-defined in Arduino.h
#undef _BV
#include <Arduino.h>
// Redefine sq macro defined by teensy3/wiring.h
#undef sq
#define sq(x) ((x)*(x))
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "fastio_Teensy.h"
#include "watchdog_Teensy.h"
#include "HAL_timers_Teensy.h"
#include <stdint.h>
#define ST7920_DELAY_1 DELAY_NS(600)
#define ST7920_DELAY_2 DELAY_NS(750)
#define ST7920_DELAY_3 DELAY_NS(750)
//#undef MOTHERBOARD
//#define MOTHERBOARD BOARD_TEENSY31_32
#define IS_32BIT_TEENSY defined(__MK20DX256__)
#define IS_TEENSY32 defined(__MK20DX256__)
#define NUM_SERIAL 1
#if SERIAL_PORT == -1
#define MYSERIAL0 SerialUSB
#elif SERIAL_PORT == 0
#define MYSERIAL0 Serial
#elif SERIAL_PORT == 1
#define MYSERIAL0 Serial1
#elif SERIAL_PORT == 2
#define MYSERIAL0 Serial2
#elif SERIAL_PORT == 3
#define MYSERIAL0 Serial3
#endif
#define HAL_SERVO_LIB libServo
typedef int8_t pin_t;
#ifndef analogInputToDigitalPin
#define analogInputToDigitalPin(p) ((p < 12u) ? (p) + 54u : -1)
#endif
#define CRITICAL_SECTION_START uint32_t primask = __get_PRIMASK(); __disable_irq()
#define CRITICAL_SECTION_END if (!primask) __enable_irq()
#define ISRS_ENABLED() (!__get_PRIMASK())
#define ENABLE_ISRS() __enable_irq()
#define DISABLE_ISRS() __disable_irq()
#ifndef strncpy_P
#define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
#endif
// Fix bug in pgm_read_ptr
#undef pgm_read_ptr
#define pgm_read_ptr(addr) (*((void**)(addr)))
// Add type-checking to pgm_read_word
#undef pgm_read_word
#define pgm_read_word(addr) (*((uint16_t*)(addr)))
#define RST_POWER_ON 1
#define RST_EXTERNAL 2
#define RST_BROWN_OUT 4
#define RST_WATCHDOG 8
#define RST_JTAG 16
#define RST_SOFTWARE 32
#define RST_BACKUP 64
// Clear the reset reason
void HAL_clear_reset_source(void);
// Get the reason for the reset
uint8_t HAL_get_reset_source(void);
FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); }
extern "C" {
int freeMemory(void);
}
// SPI: Extended functions which take 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
void spiSend(uint32_t chan, const uint8_t* buf, size_t n);
// Read single byte from specified SPI channel
uint8_t spiRec(uint32_t chan);
// ADC
void HAL_adc_init();
#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin)
#define HAL_READ_ADC() HAL_adc_get_result()
#define HAL_ADC_READY() true
#define HAL_ANALOG_SELECT(pin) NOOP;
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);
*/
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
@@ -0,0 +1,36 @@
#ifdef __MK20DX256__
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
#include "HAL_Servo_Teensy.h"
uint8_t servoPin[MAX_SERVOS] = { 0 };
int8_t libServo::attach(const int pin) {
if (this->servoIndex >= MAX_SERVOS) return -1;
if (pin > 0) servoPin[this->servoIndex] = pin;
return Servo::attach(servoPin[this->servoIndex]);
}
int8_t libServo::attach(const int pin, const int min, const int max) {
if (pin > 0) servoPin[this->servoIndex] = pin;
return Servo::attach(servoPin[this->servoIndex], min, max);
}
void libServo::move(const int value) {
constexpr uint16_t servo_delay[] = SERVO_DELAY;
static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
if (this->attach(0) >= 0) {
this->write(value);
safe_delay(servo_delay[this->servoIndex]);
#if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE)
this->detach();
#endif
}
}
#endif // HAS_SERVOS
#endif // __MK20DX256__
@@ -0,0 +1,37 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <Servo.h>
// Inherit and expand on the official library
class libServo : public Servo {
public:
int8_t attach(const int pin);
int8_t attach(const int pin, const int min, const int max);
void move(const int value);
private:
uint16_t min_ticks;
uint16_t max_ticks;
uint8_t servoIndex; // index into the channel data for this servo
};
@@ -0,0 +1,132 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef __MK20DX256__
#include "HAL.h"
#include <SPI.h>
#include <pins_arduino.h>
#include "spi_pins.h"
#include "../../core/macros.h"
static SPISettings spiConfig;
/**
* Standard SPI functions
*/
// Initialise SPI bus
void spiBegin(void) {
#if !PIN_EXISTS(SS)
#error "SS_PIN not defined!"
#endif
SET_OUTPUT(SS_PIN);
WRITE(SS_PIN, HIGH);
SET_OUTPUT(SCK_PIN);
SET_INPUT(MISO_PIN);
SET_OUTPUT(MOSI_PIN);
//#if DISABLED(SOFTWARE_SPI)
#if 0
// set SS high - may be chip select for another SPI device
#if SET_SPI_SS_HIGH
WRITE(SS_PIN, HIGH);
#endif
// set a default rate
spiInit(SPI_HALF_SPEED); // 1
#endif
}
// Configure SPI for specified SPI speed
void spiInit(uint8_t spiRate) {
// Use data rates Marlin uses
uint32_t clock;
switch (spiRate) {
case SPI_FULL_SPEED: clock = 10000000; break;
case SPI_HALF_SPEED: clock = 5000000; break;
case SPI_QUARTER_SPEED: clock = 2500000; break;
case SPI_EIGHTH_SPEED: clock = 1250000; break;
case SPI_SPEED_5: clock = 625000; break;
case SPI_SPEED_6: clock = 312500; break;
default: clock = 4000000; // Default from the SPI libarary
}
spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
SPI.begin();
}
// SPI receive a byte
uint8_t spiRec(void) {
SPI.beginTransaction(spiConfig);
const uint8_t returnByte = SPI.transfer(0xFF);
SPI.endTransaction();
return returnByte;
//SPDR = 0xFF;
//while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
//return SPDR;
}
// SPI read data
void spiRead(uint8_t* buf, uint16_t nbyte) {
SPI.beginTransaction(spiConfig);
SPI.transfer(buf, nbyte);
SPI.endTransaction();
//if (nbyte-- == 0) return;
// SPDR = 0xFF;
//for (uint16_t i = 0; i < nbyte; i++) {
// while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
// buf[i] = SPDR;
// SPDR = 0xFF;
//}
//while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
//buf[nbyte] = SPDR;
}
// SPI send a byte
void spiSend(uint8_t b) {
SPI.beginTransaction(spiConfig);
SPI.transfer(b);
SPI.endTransaction();
//SPDR = b;
//while (!TEST(SPSR, SPIF)) { /* nada */ }
}
// SPI send block
void spiSendBlock(uint8_t token, const uint8_t* buf) {
SPI.beginTransaction(spiConfig);
SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) {
while (!TEST(SPSR, SPIF)) { /* nada */ };
SPDR = buf[i];
while (!TEST(SPSR, SPIF)) { /* nada */ };
SPDR = buf[i + 1];
}
while (!TEST(SPSR, SPIF)) { /* nada */ };
SPI.endTransaction();
}
// Begin SPI transaction, set clock, bit order, data mode
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
spiConfig = SPISettings(spiClock, bitOrder, dataMode);
SPI.beginTransaction(spiConfig);
}
#endif // __MK20DX256__
@@ -0,0 +1,113 @@
/* **************************************************************************
Marlin 3D Printer Firmware
Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
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 <http://www.gnu.org/licenses/>.
****************************************************************************/
/**
* Teensy3.2 __MK20DX256__
*/
#ifdef __MK20DX256__
#include "HAL.h"
#include "HAL_timers_Teensy.h"
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
FORCE_INLINE static void __ISB(void) {
__asm__ __volatile__("isb 0xF":::"memory");
}
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
FORCE_INLINE static void __DSB(void) {
__asm__ __volatile__("dsb 0xF":::"memory");
}
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
switch (timer_num) {
case 0:
FTM0_MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
FTM0_SC = 0x00; // Set this to zero before changing the modulus
FTM0_CNT = 0x0000; // Reset the count to zero
FTM0_MOD = 0xFFFF; // max modulus = 65535
FTM0_C0V = FTM0_TIMER_RATE / frequency; // Initial FTM Channel 0 compare value
FTM0_SC = (FTM_SC_CLKS(0b1) & FTM_SC_CLKS_MASK) | (FTM_SC_PS(FTM0_TIMER_PRESCALE_BITS) & FTM_SC_PS_MASK); // Bus clock 60MHz divided by prescaler 8
FTM0_C0SC = FTM_CSC_CHIE | FTM_CSC_MSA | FTM_CSC_ELSA;
break;
case 1:
FTM1_MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN; // Disable write protection, Enable FTM1
FTM1_SC = 0x00; // Set this to zero before changing the modulus
FTM1_CNT = 0x0000; // Reset the count to zero
FTM1_MOD = 0xFFFF; // max modulus = 65535
FTM1_C0V = FTM1_TIMER_RATE / frequency; // Initial FTM Channel 0 compare value 65535
FTM1_SC = (FTM_SC_CLKS(0b1) & FTM_SC_CLKS_MASK) | (FTM_SC_PS(FTM1_TIMER_PRESCALE_BITS) & FTM_SC_PS_MASK); // Bus clock 60MHz divided by prescaler 4
FTM1_C0SC = FTM_CSC_CHIE | FTM_CSC_MSA | FTM_CSC_ELSA;
break;
}
}
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
switch(timer_num) {
case 0: NVIC_ENABLE_IRQ(IRQ_FTM0); break;
case 1: NVIC_ENABLE_IRQ(IRQ_FTM1); break;
}
}
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
switch (timer_num) {
case 0: NVIC_DISABLE_IRQ(IRQ_FTM0); break;
case 1: NVIC_DISABLE_IRQ(IRQ_FTM1); break;
}
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
switch (timer_num) {
case 0: return NVIC_IS_ENABLED(IRQ_FTM0);
case 1: return NVIC_IS_ENABLED(IRQ_FTM1);
}
return false;
}
void HAL_timer_isr_prologue(const uint8_t timer_num) {
switch(timer_num) {
case 0:
FTM0_CNT = 0x0000;
FTM0_SC &= ~FTM_SC_TOF; // Clear FTM Overflow flag
FTM0_C0SC &= ~FTM_CSC_CHF; // Clear FTM Channel Compare flag
break;
case 1:
FTM1_CNT = 0x0000;
FTM1_SC &= ~FTM_SC_TOF; // Clear FTM Overflow flag
FTM1_C0SC &= ~FTM_CSC_CHF; // Clear FTM Channel Compare flag
break;
}
}
#endif // __MK20DX256__
@@ -0,0 +1,108 @@
/* **************************************************************************
Marlin 3D Printer Firmware
Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
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 <http://www.gnu.org/licenses/>.
****************************************************************************/
/**
* Description: HAL for
* Teensy3.2 (__MK20DX256__)
*/
#pragma once
// --------------------------------------------------------------------------
// Includes
// --------------------------------------------------------------------------
#include <stdint.h>
// --------------------------------------------------------------------------
// Defines
// --------------------------------------------------------------------------
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define FTM0_TIMER_PRESCALE 8
#define FTM1_TIMER_PRESCALE 4
#define FTM0_TIMER_PRESCALE_BITS 0b011
#define FTM1_TIMER_PRESCALE_BITS 0b010
#define FTM0_TIMER_RATE (F_BUS / FTM0_TIMER_PRESCALE) // 60MHz / 8 = 7500kHz
#define FTM1_TIMER_RATE (F_BUS / FTM1_TIMER_PRESCALE) // 60MHz / 4 = 15MHz
#define HAL_TIMER_RATE (FTM0_TIMER_RATE)
#define STEP_TIMER_NUM 0
#define TEMP_TIMER_NUM 1
#define PULSE_TIMER_NUM STEP_TIMER_NUM
#define TEMP_TIMER_FREQUENCY 1000
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000)
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(STEP_TIMER_NUM)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(STEP_TIMER_NUM)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(STEP_TIMER_NUM)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM)
#define HAL_STEP_TIMER_ISR extern "C" void ftm0_isr(void) //void TC3_Handler()
#define HAL_TEMP_TIMER_ISR extern "C" void ftm1_isr(void) //void TC4_Handler()
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
switch (timer_num) {
case 0: FTM0_C0V = compare; break;
case 1: FTM1_C0V = compare; break;
}
}
FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
switch (timer_num) {
case 0: return FTM0_C0V;
case 1: return FTM1_C0V;
}
return 0;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
switch (timer_num) {
case 0: return FTM0_CNT;
case 1: return FTM1_CNT;
}
return 0;
}
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
void HAL_timer_isr_prologue(const uint8_t timer_num);
#define HAL_timer_isr_epilogue(TIMER_NUM)
@@ -0,0 +1,29 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Test TEENSY35_36 specific configuration values for errors at compile-time.
*/
#if ENABLED(EMERGENCY_PARSER)
#error "EMERGENCY_PARSER is not yet implemented for Teensy 3.1/3.2. Disable EMERGENCY_PARSER to continue."
#endif
@@ -0,0 +1,86 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Endstop Interrupts
*
* Without endstop interrupts the endstop pins must be polled continually in
* the temperature-ISR via endstops.update(), most of the time finding no change.
* With this feature endstops.update() is called only when we know that at
* least one endstop has changed state, saving valuable CPU cycles.
*
* This feature only works when all used endstop pins can generate an 'external interrupt'.
*
* Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'.
* (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino)
*/
#pragma once
#include "../../module/endstops.h"
// One ISR for all EXT-Interrupts
void endstop_ISR(void) { endstops.update(); }
/**
* Endstop interrupts for Due based targets.
* On Due, all pins support external interrupt capability.
*/
void setup_endstop_interrupts( void ) {
#if HAS_X_MAX
attachInterrupt(digitalPinToInterrupt(X_MAX_PIN), endstop_ISR, CHANGE); // assign it
#endif
#if HAS_X_MIN
attachInterrupt(digitalPinToInterrupt(X_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Y_MAX
attachInterrupt(digitalPinToInterrupt(Y_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Y_MIN
attachInterrupt(digitalPinToInterrupt(Y_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MAX
attachInterrupt(digitalPinToInterrupt(Z_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN
attachInterrupt(digitalPinToInterrupt(Z_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z2_MAX
attachInterrupt(digitalPinToInterrupt(Z2_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z2_MIN
attachInterrupt(digitalPinToInterrupt(Z2_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(digitalPinToInterrupt(Z_MIN_PROBE_PIN), endstop_ISR, CHANGE);
#endif
}
@@ -0,0 +1,92 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Fast I/O Routines for Teensy 3.5 and Teensy 3.6
* Use direct port manipulation to save scads of processor time.
* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.
*/
#pragma once
#ifndef MASK
#define MASK(PIN) (1 << PIN)
#endif
#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000)
#define GPIO_BITBAND(reg, bit) (*(uint32_t *)GPIO_BITBAND_ADDR((reg), (bit)))
/**
* Magic I/O routines
*
* Now you can simply SET_OUTPUT(PIN); WRITE(PIN, HIGH); WRITE(PIN, LOW);
*
* Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
#define _READ(p) bool(CORE_PIN ## p ## _PINREG & CORE_PIN ## p ## _BITMASK)
#define _WRITE(P,V) do{ \
if (V) CORE_PIN ## P ## _PORTSET = CORE_PIN ## P ## _BITMASK; \
else CORE_PIN ## P ## _PORTCLEAR = CORE_PIN ## P ## _BITMASK; \
}while(0)
#define _TOGGLE(P) (*(&(CORE_PIN ## P ## _PORTCLEAR)+1) = CORE_PIN ## P ## _BITMASK)
#define _SET_INPUT(P) do{ \
CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1); \
GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \
}while(0)
#define _SET_OUTPUT(P) do{ \
CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \
GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 1; \
}while(0)
#define _SET_INPUT_PULLUP(P) do{ \
CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; \
GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \
}while(0)
#define _GET_INPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0)
#define _GET_OUTPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0)
#define READ(IO) _READ(IO)
#define WRITE_VAR(IO,V) _WRITE_VAR(IO,V)
#define WRITE(IO,V) _WRITE(IO,V)
#define TOGGLE(IO) _TOGGLE(IO)
#define SET_INPUT(IO) _SET_INPUT(IO)
#define SET_INPUT_PULLUP(IO) _SET_INPUT_PULLUP(IO)
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
#define GET_INPUT(IO) _GET_INPUT(IO)
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
/**
* Ports, functions, and pins
*/
#define DIO0_PIN 8
@@ -0,0 +1,51 @@
#ifdef __MK20DX256__
#include "../../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../persistent_store_api.h"
namespace HAL {
namespace PersistentStore {
bool access_start() { return true; }
bool access_finish() { return true; }
bool write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
// EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v);
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((unsigned char*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
} // PersistentStore
} // HAL
#endif // EEPROM_SETTINGS
#endif // __MK20DX256__
@@ -0,0 +1 @@
#error "Debug pins is not supported on the Teensy 3.1 / 3.2 Platform!"
+28
View File
@@ -0,0 +1,28 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#define SCK_PIN 13
#define MISO_PIN 12
#define MOSI_PIN 11
#define SS_PIN 20 //SDSS // A.28, A.29, B.21, C.26, C.29
@@ -0,0 +1,39 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef __MK20DX256__
#include "../../inc/MarlinConfig.h"
#if ENABLED(USE_WATCHDOG)
#include "watchdog_Teensy.h"
void watchdog_init() {
WDOG_TOVALH = 0;
WDOG_TOVALL = 4000;
WDOG_STCTRLH = WDOG_STCTRLH_WDOGEN;
}
#endif // USE_WATCHDOG
#endif // __MK20DX256__
@@ -0,0 +1,35 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "HAL.h"
// Arduino Due core now has watchdog support
void watchdog_init();
inline void watchdog_reset() {
// Watchdog refresh sequence
WDOG_REFRESH = 0xA602;
WDOG_REFRESH = 0xB480;
}
+1 -1
View File
@@ -26,7 +26,7 @@
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#include "HAL.h"
#include "../Delay.h"
#include "../shared/Delay.h"
#include <Wire.h>
+2 -2
View File
@@ -42,8 +42,8 @@
#undef sq
#define sq(x) ((x)*(x))
#include "../math_32bit.h"
#include "../HAL_SPI.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio_Teensy.h"
#include "watchdog_Teensy.h"
@@ -9,7 +9,7 @@
static SPISettings spiConfig;
// Standard SPI functions
/** Initialise SPI bus */
/** Initialize SPI bus */
void spiBegin(void) {
#if !PIN_EXISTS(SS)
#error SS_PIN not defined!
@@ -102,11 +102,6 @@ FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
return 0;
}
FORCE_INLINE static void HAL_timer_restrain(const uint8_t timer_num, const uint16_t interval_ticks) {
const hal_timer_t mincmp = HAL_timer_get_count(timer_num) + interval_ticks;
if (HAL_timer_get_compare(timer_num) < mincmp) HAL_timer_set_compare(timer_num, mincmp);
}
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
@@ -43,44 +43,40 @@
void endstop_ISR(void) { endstops.update(); }
/**
* Endstop interrupts for Due based targets.
* On Due, all pins support external interrupt capability.
* Endstop interrupts for Due based targets.
* On Due, all pins support external interrupt capability.
*/
void setup_endstop_interrupts( void ) {
#if HAS_X_MAX
attachInterrupt(digitalPinToInterrupt(X_MAX_PIN), endstop_ISR, CHANGE); // assign it
#endif
#if HAS_X_MIN
attachInterrupt(digitalPinToInterrupt(X_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Y_MAX
attachInterrupt(digitalPinToInterrupt(Y_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Y_MIN
attachInterrupt(digitalPinToInterrupt(Y_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MAX
attachInterrupt(digitalPinToInterrupt(Z_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN
attachInterrupt(digitalPinToInterrupt(Z_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z2_MAX
attachInterrupt(digitalPinToInterrupt(Z2_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z2_MIN
attachInterrupt(digitalPinToInterrupt(Z2_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MAX
attachInterrupt(digitalPinToInterrupt(Z3_MAX_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z3_MIN
attachInterrupt(digitalPinToInterrupt(Z3_MIN_PIN), endstop_ISR, CHANGE);
#endif
#if HAS_Z_MIN_PROBE_PIN
attachInterrupt(digitalPinToInterrupt(Z_MIN_PROBE_PIN), endstop_ISR, CHANGE);
#endif
@@ -0,0 +1,71 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#include "../../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../shared/persistent_store_api.h"
#include <avr/eeprom.h>
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
// EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed!
if (v != eeprom_read_byte(p)) {
eeprom_write_byte(p, v);
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
};
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((unsigned char*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
size_t PersistentStore::capacity() { return E2END + 1; }
#endif // EEPROM_SETTINGS
#endif // __MK64FX512__ || __MK66FX1M0__
@@ -4,7 +4,7 @@
#if ENABLED(EEPROM_SETTINGS)
#include "../persistent_store_api.h"
#include "../shared/persistent_store_api.h"
namespace HAL {
namespace PersistentStore {
+2
View File
@@ -7,6 +7,8 @@
#define HAL_PLATFORM HAL_AVR
#elif defined(ARDUINO_ARCH_SAM)
#define HAL_PLATFORM HAL_DUE
#elif defined(__MK20DX256__)
#define HAL_PLATFORM HAL_TEENSY31_32
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define HAL_PLATFORM HAL_TEENSY35_36
#elif defined(TARGET_LPC1768)
+148
View File
@@ -0,0 +1,148 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Busy wait delay cycles routines:
*
* DELAY_CYCLES(count): Delay execution in cycles
* DELAY_NS(count): Delay execution in nanoseconds
* DELAY_US(count): Delay execution in microseconds
*/
#ifndef MARLIN_DELAY_H
#define MARLIN_DELAY_H
#include "../../core/macros.h"
#if defined(__arm__) || defined(__thumb__)
// https://blueprints.launchpad.net/gcc-arm-embedded/+spec/delay-cycles
#define nop() __asm__ __volatile__("nop;\n\t":::)
FORCE_INLINE static void __delay_4cycles(uint32_t cy) { // +1 cycle
#if ARCH_PIPELINE_RELOAD_CYCLES < 2
#define EXTRA_NOP_CYCLES A("nop")
#else
#define EXTRA_NOP_CYCLES ""
#endif
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("1")
A("subs %[cnt],#1")
EXTRA_NOP_CYCLES
A("bne 1b")
: [cnt]"+r"(cy) // output: +r means input+output
: // input:
: "cc" // clobbers:
);
}
// Delay in cycles
FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
if (__builtin_constant_p(x)) {
#define MAXNOPS 4
if (x <= (MAXNOPS)) {
switch (x) { case 4: nop(); case 3: nop(); case 2: nop(); case 1: nop(); }
}
else { // because of +1 cycle inside delay_4cycles
const uint32_t rem = (x - 1) % (MAXNOPS);
switch (rem) { case 3: nop(); case 2: nop(); case 1: nop(); }
if ((x = (x - 1) / (MAXNOPS)))
__delay_4cycles(x); // if need more then 4 nop loop is more optimal
}
#undef MAXNOPS
}
else if ((x >>= 2))
__delay_4cycles(x);
}
#undef nop
#elif defined(__AVR__)
#define nop() __asm__ __volatile__("nop;\n\t":::)
FORCE_INLINE static void __delay_4cycles(uint8_t cy) {
__asm__ __volatile__(
L("1")
A("dec %[cnt]")
A("nop")
A("brne 1b")
: [cnt] "+r"(cy) // output: +r means input+output
: // input:
: "cc" // clobbers:
);
}
// Delay in cycles
FORCE_INLINE static void DELAY_CYCLES(uint16_t x) {
if (__builtin_constant_p(x)) {
#define MAXNOPS 4
if (x <= (MAXNOPS)) {
switch (x) { case 4: nop(); case 3: nop(); case 2: nop(); case 1: nop(); }
}
else {
const uint32_t rem = (x) % (MAXNOPS);
switch (rem) { case 3: nop(); case 2: nop(); case 1: nop(); }
if ((x = (x) / (MAXNOPS)))
__delay_4cycles(x); // if need more then 4 nop loop is more optimal
}
#undef MAXNOPS
}
else if ((x >>= 2))
__delay_4cycles(x);
}
#undef nop
#elif defined(ESP32)
FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
unsigned long ccount, stop;
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
stop = ccount + x; // This can overflow
while (ccount < stop) { // This doesn't deal with overflows
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
}
}
#else
#error "Unsupported MCU architecture"
#endif
// Delay in nanoseconds
#define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU/1000000L) / 1000L )
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES( (x) * (F_CPU/1000000L) )
#endif // MARLIN_DELAY_H
+82
View File
@@ -0,0 +1,82 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* HAL/HAL_SPI.h
* Core Marlin definitions for SPI, implemented in the HALs
*/
#ifndef _HAL_SPI_H_
#define _HAL_SPI_H_
#include <stdint.h>
/**
* SPI speed where 0 <= index <= 6
*
* Approximate rates :
*
* 0 : 8 - 10 MHz
* 1 : 4 - 5 MHz
* 2 : 2 - 2.5 MHz
* 3 : 1 - 1.25 MHz
* 4 : 500 - 625 kHz
* 5 : 250 - 312 kHz
* 6 : 125 - 156 kHz
*
* On AVR, actual speed is F_CPU/2^(1 + index).
* On other platforms, speed should be in range given above where possible.
*/
#define SPI_FULL_SPEED 0 // Set SCK to max rate
#define SPI_HALF_SPEED 1 // Set SCK rate to half of max rate
#define SPI_QUARTER_SPEED 2 // Set SCK rate to quarter of max rate
#define SPI_EIGHTH_SPEED 3 // Set SCK rate to 1/8 of max rate
#define SPI_SIXTEENTH_SPEED 4 // Set SCK rate to 1/16 of max rate
#define SPI_SPEED_5 5 // Set SCK rate to 1/32 of max rate
#define SPI_SPEED_6 6 // Set SCK rate to 1/64 of max rate
#define SPI_LSBFIRST 0
#define SPI_MSBFIRST 1
#define SPI_DATAMODE_0 0x00
#define SPI_DATAMODE_1 0x04
#define SPI_DATAMODE_2 0x08
#define SPI_DATAMODE_3 0x0C
// Standard SPI functions
/** Initialize SPI bus */
void spiBegin(void);
/** Configure SPI for specified SPI speed */
void spiInit(uint8_t spiRate);
/** Write single byte to SPI */
void spiSend(uint8_t b);
/** Read single byte from SPI */
uint8_t spiRec(void);
/** Read from SPI into buffer */
void spiRead(uint8_t* buf, uint16_t nbyte);
/** Write token and then write from 512 byte buffer to SPI (for SD card) */
void spiSendBlock(uint8_t token, const uint8_t* buf);
/** Begin SPI transaction, set clock, bit order, data mode */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode);
#endif // _HAL_SPI_H_
+159
View File
@@ -0,0 +1,159 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Description: functions for I2C connected external EEPROM.
* Not platform dependent.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(I2C_EEPROM)
// --------------------------------------------------------------------------
// Includes
// --------------------------------------------------------------------------
#include HAL_PATH(.., HAL.h)
#include <Wire.h>
// --------------------------------------------------------------------------
// Externals
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Local defines
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Types
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Variables
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Public Variables
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Private Variables
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Function prototypes
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Private functions
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// Public functions
// --------------------------------------------------------------------------
static uint8_t eeprom_device_address = 0x50;
static void eeprom_init(void) {
static bool eeprom_initialized = false;
if (!eeprom_initialized) {
Wire.begin();
eeprom_initialized = true;
}
}
void eeprom_write_byte(unsigned char *pos, unsigned char value) {
unsigned eeprom_address = (unsigned) pos;
eeprom_init();
Wire.beginTransmission(eeprom_device_address);
Wire.write((int)(eeprom_address >> 8)); // MSB
Wire.write((int)(eeprom_address & 0xFF)); // LSB
Wire.write(value);
Wire.endTransmission();
// wait for write cycle to complete
// this could be done more efficiently with "acknowledge polling"
delay(5);
}
// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void eeprom_update_block(const void *pos, void* eeprom_address, size_t n) {
eeprom_init();
Wire.beginTransmission(eeprom_device_address);
Wire.write((int)((unsigned)eeprom_address >> 8)); // MSB
Wire.write((int)((unsigned)eeprom_address & 0xFF)); // LSB
Wire.endTransmission();
uint8_t *ptr = (uint8_t*)pos;
uint8_t flag = 0;
Wire.requestFrom(eeprom_device_address, (byte)n);
for (byte c = 0; c < n && Wire.available(); c++)
flag |= Wire.read() ^ ptr[c];
if (flag) {
Wire.beginTransmission(eeprom_device_address);
Wire.write((int)((unsigned)eeprom_address >> 8)); // MSB
Wire.write((int)((unsigned)eeprom_address & 0xFF)); // LSB
Wire.write((uint8_t*)pos, n);
Wire.endTransmission();
// wait for write cycle to complete
// this could be done more efficiently with "acknowledge polling"
delay(5);
}
}
unsigned char eeprom_read_byte(unsigned char *pos) {
byte data = 0xFF;
unsigned eeprom_address = (unsigned)pos;
eeprom_init();
Wire.beginTransmission(eeprom_device_address);
Wire.write((int)(eeprom_address >> 8)); // MSB
Wire.write((int)(eeprom_address & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(eeprom_device_address, (byte)1);
return Wire.available() ? Wire.read() : 0xFF;
}
// maybe let's not read more than 30 or 32 bytes at a time!
void eeprom_read_block(void* pos, const void* eeprom_address, size_t n) {
eeprom_init();
Wire.beginTransmission(eeprom_device_address);
Wire.write((int)((unsigned)eeprom_address >> 8)); // MSB
Wire.write((int)((unsigned)eeprom_address & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(eeprom_device_address, (byte)n);
for (byte c = 0; c < n; c++ )
if (Wire.available()) *((uint8_t*)pos + c) = Wire.read();
}
#endif // ENABLED(I2C_EEPROM)
+119
View File
@@ -0,0 +1,119 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Description: functions for SPI connected external EEPROM.
* Not platform dependent.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(SPI_EEPROM)
#include HAL_PATH(.., HAL.h)
#define CMD_WREN 6 // WREN
#define CMD_READ 2 // WRITE
#define CMD_WRITE 2 // WRITE
uint8_t eeprom_read_byte(uint8_t* pos) {
uint8_t v;
uint8_t eeprom_temp[3];
// set read location
// begin transmission from device
eeprom_temp[0] = CMD_READ;
eeprom_temp[1] = ((unsigned)pos>>8) & 0xFF; // addr High
eeprom_temp[2] = (unsigned)pos& 0xFF; // addr Low
WRITE(SPI_EEPROM1_CS, HIGH);
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
v = spiRec(SPI_CHAN_EEPROM1);
WRITE(SPI_EEPROM1_CS, HIGH);
return v;
}
void eeprom_read_block(void* dest, const void* eeprom_address, size_t n) {
uint8_t eeprom_temp[3];
// set read location
// begin transmission from device
eeprom_temp[0] = CMD_READ;
eeprom_temp[1] = ((unsigned)eeprom_address>>8) & 0xFF; // addr High
eeprom_temp[2] = (unsigned)eeprom_address& 0xFF; // addr Low
WRITE(SPI_EEPROM1_CS, HIGH);
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
uint8_t *p_dest = (uint8_t *)dest;
while (n--)
*p_dest++ = spiRec(SPI_CHAN_EEPROM1);
WRITE(SPI_EEPROM1_CS, HIGH);
}
void eeprom_write_byte(uint8_t* pos, uint8_t value) {
uint8_t eeprom_temp[3];
/*write enable*/
eeprom_temp[0] = CMD_WREN;
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 1);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(1);
/*write addr*/
eeprom_temp[0] = CMD_WRITE;
eeprom_temp[1] = ((unsigned)pos>>8) & 0xFF; //addr High
eeprom_temp[2] = (unsigned)pos & 0xFF; //addr Low
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
spiSend(SPI_CHAN_EEPROM1, value);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(7); // wait for page write to complete
}
void eeprom_update_block(const void* src, void* eeprom_address, size_t n) {
uint8_t eeprom_temp[3];
/*write enable*/
eeprom_temp[0] = CMD_WREN;
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 1);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(1);
/*write addr*/
eeprom_temp[0] = CMD_WRITE;
eeprom_temp[1] = ((unsigned)eeprom_address>>8) & 0xFF; //addr High
eeprom_temp[2] = (unsigned)eeprom_address & 0xFF; //addr Low
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
spiSend(SPI_CHAN_EEPROM1, (const uint8_t*)src, n);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(7); // wait for page write to complete
}
#endif // ENABLED(SPI_EEPROM)
@@ -0,0 +1,101 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 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 <http://www.gnu.org/licenses/>.
*
*/
#include "backtrace.h"
#if defined(__arm__) || defined(__thumb__)
#include "unwinder.h"
#include "unwmemaccess.h"
#include "../../../core/serial.h"
#include <stdarg.h>
// Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) {
int *p = (int*)ctx;
(*p)++;
SERIAL_CHAR('#'); SERIAL_PRINT(*p,DEC); SERIAL_ECHOPGM(" : ");
SERIAL_ECHOPGM(bte->name ? bte->name : "unknown"); SERIAL_ECHOPGM("@0x"); SERIAL_PRINT(bte->function, HEX);
SERIAL_CHAR('+'); SERIAL_PRINT(bte->address - bte->function,DEC);
SERIAL_ECHOPGM(" PC:"); SERIAL_PRINT(bte->address,HEX); SERIAL_CHAR('\n');
return true;
}
#ifdef UNW_DEBUG
void UnwPrintf(const char* format, ...) {
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
TX(&dest[0]);
}
#endif
/* Table of function pointers for passing to the unwinder */
static const UnwindCallbacks UnwCallbacks = {
UnwReportOut,
UnwReadW,
UnwReadH,
UnwReadB
#ifdef UNW_DEBUG
, UnwPrintf
#endif
};
void backtrace(void) {
UnwindFrame btf;
uint32_t sp = 0, lr = 0, pc = 0;
// Capture the values of the registers to perform the traceback
__asm__ __volatile__ (
" mov %[lrv],lr\n"
" mov %[spv],sp\n"
" mov %[pcv],pc\n"
: [spv]"+r"( sp ),
[lrv]"+r"( lr ),
[pcv]"+r"( pc )
::
);
// Fill the traceback structure
btf.sp = sp;
btf.fp = btf.sp;
btf.lr = lr;
btf.pc = pc | 1; // Force Thumb, as CORTEX only support it
// Perform a backtrace
SERIAL_ERROR_START();
SERIAL_ERRORLNPGM("Backtrace:");
int ctr = 0;
UnwindStart(&btf, &UnwCallbacks, &ctr);
}
#else // !__arm__ && !__thumb__
void backtrace(void) {}
#endif
@@ -0,0 +1,29 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef _BACKTRACE_H_
#define _BACKTRACE_H_
// Perform a backtrace to the serial port
void backtrace(void);
#endif
+175
View File
@@ -0,0 +1,175 @@
/***************************************************************************
* ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
* Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
*
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
***************************************************************************
* File Description: Utility functions and glue for ARM unwinding sub-modules.
**************************************************************************/
#if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWARM"
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "unwarm.h"
#include "unwarmmem.h"
#if defined(UNW_DEBUG)
/**
* Printf wrapper.
* This is used such that alternative outputs for any output can be selected
* by modification of this wrapper function.
*/
void UnwPrintf(const char *format, ...) {
va_list args;
va_start( args, format );
vprintf(format, args );
}
#endif
/**
* Invalidate all general purpose registers.
*/
void UnwInvalidateRegisterFile(RegData *regFile) {
uint8_t t = 0;
do {
regFile[t].o = REG_VAL_INVALID;
t++;
} while (t < 13);
}
/**
* Initialize the data used for unwinding.
*/
void UnwInitState(UnwState * const state, /**< Pointer to structure to fill. */
const UnwindCallbacks *cb, /**< Callbacks. */
void *rptData, /**< Data to pass to report function. */
uint32_t pcValue, /**< PC at which to start unwinding. */
uint32_t spValue) { /**< SP at which to start unwinding. */
UnwInvalidateRegisterFile(state->regData);
/* Store the pointer to the callbacks */
state->cb = cb;
state->reportData = rptData;
/* Setup the SP and PC */
state->regData[13].v = spValue;
state->regData[13].o = REG_VAL_FROM_CONST;
state->regData[15].v = pcValue;
state->regData[15].o = REG_VAL_FROM_CONST;
UnwPrintd3("\nInitial: PC=0x%08x SP=0x%08x\n", pcValue, spValue);
/* Invalidate all memory addresses */
memset(state->memData.used, 0, sizeof(state->memData.used));
}
// Detect if function names are available
static int __attribute__ ((noinline)) has_function_names(void) {
uint32_t flag_word = ((uint32_t*)(((uint32_t)(&has_function_names)) & (-4))) [-1];
return ((flag_word & 0xFF000000) == 0xFF000000) ? 1 : 0;
}
/**
* Call the report function to indicate some return address.
* This returns the value of the report function, which if true
* indicates that unwinding may continue.
*/
bool UnwReportRetAddr(UnwState * const state, uint32_t addr) {
UnwReport entry;
// We found two acceptable values.
entry.name = NULL;
entry.address = addr & 0xFFFFFFFE; // Remove Thumb bit
entry.function = 0;
// If there are function names, try to solve name
if (has_function_names()) {
// Lets find the function name, if possible
// Align address to 4 bytes
uint32_t pf = addr & (-4);
// Scan backwards until we find the function name
uint32_t v;
while (state->cb->readW(pf-4,&v)) {
// Check if name descriptor is valid
if ((v & 0xFFFFFF00) == 0xFF000000 && (v & 0xFF) > 1) {
// Assume the name was found!
entry.name = ((const char*)pf) - 4 - (v & 0xFF);
entry.function = pf;
break;
}
// Go backwards to the previous word
pf -= 4;
}
}
/* Cast away const from reportData.
* The const is only to prevent the unw module modifying the data.
*/
return state->cb->report((void *)state->reportData, &entry);
}
/**
* Write some register to memory.
* This will store some register and meta data onto the virtual stack.
* The address for the write
* \param state [in/out] The unwinding state.
* \param wAddr [in] The address at which to write the data.
* \param reg [in] The register to store.
* \return true if the write was successful, false otherwise.
*/
bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegData * const reg) {
return UnwMemHashWrite(&state->memData, addr, reg->v, M_IsOriginValid(reg->o));
}
/**
* Read a register from memory.
* This will read a register from memory, and setup the meta data.
* If the register has been previously written to memory using
* UnwMemWriteRegister, the local hash will be used to return the
* value while respecting whether the data was valid or not. If the
* register was previously written and was invalid at that point,
* REG_VAL_INVALID will be returned in *reg.
* \param state [in] The unwinding state.
* \param addr [in] The address to read.
* \param reg [out] The result, containing the data value and the origin
* which will be REG_VAL_FROM_MEMORY, or REG_VAL_INVALID.
* \return true if the address could be read and *reg has been filled in.
* false is the data could not be read.
*/
bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg) {
bool tracked;
// Check if the value can be found in the hash
if (UnwMemHashRead(&state->memData, addr, &reg->v, &tracked)) {
reg->o = tracked ? REG_VAL_FROM_MEMORY : REG_VAL_INVALID;
return true;
}
else if (state->cb->readW(addr, &reg->v)) { // Not in the hash, so read from real memory
reg->o = REG_VAL_FROM_MEMORY;
return true;
}
else return false; // Not in the hash, and failed to read from memory
}
#endif // __arm__ || __thumb__
+143
View File
@@ -0,0 +1,143 @@
/***************************************************************************
* ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
*
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
***************************************************************************
* File Description: Internal interface between the ARM unwinding sub-modules.
**************************************************************************/
#ifndef UNWARM_H
#define UNWARM_H
#include "unwinder.h"
/** The maximum number of instructions to interpet in a function.
* Unwinding will be unconditionally stopped and UNWIND_EXHAUSTED returned
* if more than this number of instructions are interpreted in a single
* function without unwinding a stack frame. This prevents infinite loops
* or corrupted program memory from preventing unwinding from progressing.
*/
#define UNW_MAX_INSTR_COUNT 500
/** The size of the hash used to track reads and writes to memory.
* This should be a prime value for efficiency.
*/
#define MEM_HASH_SIZE 31
/***************************************************************************
* Type Definitions
**************************************************************************/
typedef enum {
/** Invalid value. */
REG_VAL_INVALID = 0x00,
REG_VAL_FROM_STACK = 0x01,
REG_VAL_FROM_MEMORY = 0x02,
REG_VAL_FROM_CONST = 0x04,
REG_VAL_ARITHMETIC = 0x80
} RegValOrigin;
/** Type for tracking information about a register.
* This stores the register value, as well as other data that helps unwinding.
*/
typedef struct {
/** The value held in the register. */
uint32_t v;
/** The origin of the register value.
* This is used to track how the value in the register was loaded.
*/
int o; /* (RegValOrigin) */
} RegData;
/** Structure used to track reads and writes to memory.
* This structure is used as a hash to store a small number of writes
* to memory.
*/
typedef struct {
/** Memory contents. */
uint32_t v[MEM_HASH_SIZE];
/** Address at which v[n] represents. */
uint32_t a[MEM_HASH_SIZE];
/** Indicates whether the data in v[n] and a[n] is occupied.
* Each bit represents one hash value.
*/
uint8_t used[(MEM_HASH_SIZE + 7) / 8];
/** Indicates whether the data in v[n] is valid.
* This allows a[n] to be set, but for v[n] to be marked as invalid.
* Specifically this is needed for when an untracked register value
* is written to memory.
*/
uint8_t tracked[(MEM_HASH_SIZE + 7) / 8];
} MemData;
/** Structure that is used to keep track of unwinding meta-data.
* This data is passed between all the unwinding functions.
*/
typedef struct {
/** The register values and meta-data. */
RegData regData[16];
/** Memory tracking data. */
MemData memData;
/** Pointer to the callback functions */
const UnwindCallbacks *cb;
/** Pointer to pass to the report function. */
const void *reportData;
} UnwState;
/***************************************************************************
* Macros
**************************************************************************/
#define M_IsOriginValid(v) (((v) & 0x7F) ? true : false)
#define M_Origin2Str(v) ((v) ? "VALID" : "INVALID")
#if defined(UNW_DEBUG)
#define UnwPrintd1(a) state->cb->printf(a)
#define UnwPrintd2(a,b) state->cb->printf(a,b)
#define UnwPrintd3(a,b,c) state->cb->printf(a,b,c)
#define UnwPrintd4(a,b,c,d) state->cb->printf(a,b,c,d)
#define UnwPrintd5(a,b,c,d,e) state->cb->printf(a,b,c,d,e)
#define UnwPrintd6(a,b,c,d,e,f) state->cb->printf(a,b,c,d,e,f)
#define UnwPrintd7(a,b,c,d,e,f,g) state->cb->printf(a,b,c,d,e,f,g)
#define UnwPrintd8(a,b,c,d,e,f,g,h) state->cb->printf(a,b,c,d,e,f,g,h)
#else
#define UnwPrintd1(a)
#define UnwPrintd2(a,b)
#define UnwPrintd3(a,b,c)
#define UnwPrintd4(a,b,c,d)
#define UnwPrintd5(a,b,c,d,e)
#define UnwPrintd6(a,b,c,d,e,f)
#define UnwPrintd7(a,b,c,d,e,f,g)
#define UnwPrintd8(a,b,c,d,e,f,g,h)
#endif
/***************************************************************************
* Function Prototypes
**************************************************************************/
UnwResult UnwStartArm(UnwState * const state);
UnwResult UnwStartThumb(UnwState * const state);
void UnwInvalidateRegisterFile(RegData *regFile);
void UnwInitState(UnwState * const state, const UnwindCallbacks *cb, void *rptData, uint32_t pcValue, uint32_t spValue);
bool UnwReportRetAddr(UnwState * const state, uint32_t addr);
bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegData * const reg);
bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg);
void UnwMemHashGC(UnwState * const state);
#endif // UNWARM_H
@@ -0,0 +1,597 @@
/***************************************************************************
* ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
* Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
*
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
***************************************************************************
* File Description: Abstract interpreter for ARM mode.
**************************************************************************/
#if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWARM_ARM"
#include <stdio.h>
#include "unwarm.h"
/** Check if some instruction is a data-processing instruction.
* Decodes the passed instruction, checks if it is a data-processing and
* verifies that the parameters and operation really indicate a data-
* processing instruction. This is needed because some parts of the
* instruction space under this instruction can be extended or represent
* other operations such as MRS, MSR.
*
* \param[in] inst The instruction word.
* \retval true Further decoding of the instruction indicates that this is
* a valid data-processing instruction.
* \retval false This is not a data-processing instruction,
*/
static bool isDataProc(uint32_t instr) {
uint8_t opcode = (instr & 0x01E00000) >> 21;
bool S = (instr & 0x00100000) ? true : false;
if ((instr & 0xFC000000) != 0xE0000000) {
return false;
}
else if (!S && opcode >= 8 && opcode <= 11) {
/* TST, TEQ, CMP and CMN all require S to be set */
return false;
}
else
return true;
}
UnwResult UnwStartArm(UnwState * const state) {
bool found = false;
uint16_t t = UNW_MAX_INSTR_COUNT;
do {
uint32_t instr;
/* Attempt to read the instruction */
if (!state->cb->readW(state->regData[15].v, &instr)) {
return UNWIND_IREAD_W_FAIL;
}
UnwPrintd4("A %x %x %08x:", state->regData[13].v, state->regData[15].v, instr);
/* Check that the PC is still on Arm alignment */
if (state->regData[15].v & 0x3) {
UnwPrintd1("\nError: PC misalignment\n");
return UNWIND_INCONSISTENT;
}
/* Check that the SP and PC have not been invalidated */
if (!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) {
UnwPrintd1("\nError: PC or SP invalidated\n");
return UNWIND_INCONSISTENT;
}
/* Branch and Exchange (BX)
* This is tested prior to data processing to prevent
* mis-interpretation as an invalid TEQ instruction.
*/
if ((instr & 0xFFFFFFF0) == 0xE12FFF10) {
uint8_t rn = instr & 0xF;
UnwPrintd4("BX r%d\t ; r%d %s\n", rn, rn, M_Origin2Str(state->regData[rn].o));
if (!M_IsOriginValid(state->regData[rn].o)) {
UnwPrintd1("\nUnwind failure: BX to untracked register\n");
return UNWIND_FAILURE;
}
/* Set the new PC value */
state->regData[15].v = state->regData[rn].v;
/* Check if the return value is from the stack */
if (state->regData[rn].o == REG_VAL_FROM_STACK) {
/* Now have the return address */
UnwPrintd2(" Return PC=%x\n", state->regData[15].v & (~0x1));
/* Report the return address */
if (!UnwReportRetAddr(state, state->regData[rn].v))
return UNWIND_TRUNCATED;
}
/* Determine the return mode */
if (state->regData[rn].v & 0x1) {
/* Branching to THUMB */
return UnwStartThumb(state);
}
else {
/* Branch to ARM */
/* Account for the auto-increment which isn't needed */
state->regData[15].v -= 4;
}
}
/* Branch */
else if ((instr & 0xFF000000) == 0xEA000000) {
int32_t offset = (instr & 0x00FFFFFF);
/* Shift value */
offset = offset << 2;
/* Sign extend if needed */
if (offset & 0x02000000) {
offset |= 0xFC000000;
}
UnwPrintd2("B %d\n", offset);
/* Adjust PC */
state->regData[15].v += offset;
/* Account for pre-fetch, where normally the PC is 8 bytes
* ahead of the instruction just executed.
*/
state->regData[15].v += 4;
}
/* MRS */
else if ((instr & 0xFFBF0FFF) == 0xE10F0000) {
#if defined(UNW_DEBUG)
bool R = (instr & 0x00400000) ? true : false;
#endif
uint8_t rd = (instr & 0x0000F000) >> 12;
UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
/* Status registers untracked */
state->regData[rd].o = REG_VAL_INVALID;
}
/* MSR */
else if ((instr & 0xFFB0F000) == 0xE120F000) {
#if defined(UNW_DEBUG)
bool R = (instr & 0x00400000) ? true : false;
UnwPrintd2("MSR %s_?, ???", R ? "SPSR" : "CPSR");
#endif
/* Status registers untracked.
* Potentially this could change processor mode and switch
* banked registers r8-r14. Most likely is that r13 (sp) will
* be banked. However, invalidating r13 will stop unwinding
* when potentially this write is being used to disable/enable
* interrupts (a common case). Therefore no invalidation is
* performed.
*/
}
/* Data processing */
else if (isDataProc(instr)) {
bool I = (instr & 0x02000000) ? true : false;
uint8_t opcode = (instr & 0x01E00000) >> 21;
#if defined(UNW_DEBUG)
bool S = (instr & 0x00100000) ? true : false;
#endif
uint8_t rn = (instr & 0x000F0000) >> 16;
uint8_t rd = (instr & 0x0000F000) >> 12;
uint16_t operand2 = (instr & 0x00000FFF);
uint32_t op2val;
int op2origin;
switch(opcode) {
case 0: UnwPrintd4("AND%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 1: UnwPrintd4("EOR%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 2: UnwPrintd4("SUB%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 3: UnwPrintd4("RSB%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 4: UnwPrintd4("ADD%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 5: UnwPrintd4("ADC%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 6: UnwPrintd4("SBC%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 7: UnwPrintd4("RSC%s r%d,r%d,", S ? "S" : "", rd, rn); break;
case 8: UnwPrintd3("TST%s r%d,", S ? "S" : "", rn); break;
case 9: UnwPrintd3("TEQ%s r%d,", S ? "S" : "", rn); break;
case 10: UnwPrintd3("CMP%s r%d,", S ? "S" : "", rn); break;
case 11: UnwPrintd3("CMN%s r%d,", S ? "S" : "", rn); break;
case 12: UnwPrintd3("ORR%s r%d,", S ? "S" : "", rn); break;
case 13: UnwPrintd3("MOV%s r%d,", S ? "S" : "", rd); break;
case 14: UnwPrintd4("BIC%s r%d,r%d", S ? "S" : "", rd, rn); break;
case 15: UnwPrintd3("MVN%s r%d,", S ? "S" : "", rd); break;
}
/* Decode operand 2 */
if (I) {
uint8_t shiftDist = (operand2 & 0x0F00) >> 8;
uint8_t shiftConst = (operand2 & 0x00FF);
/* rotate const right by 2 * shiftDist */
shiftDist *= 2;
op2val = (shiftConst >> shiftDist) |
(shiftConst << (32 - shiftDist));
op2origin = REG_VAL_FROM_CONST;
UnwPrintd2("#0x%x", op2val);
}
else {
/* Register and shift */
uint8_t rm = (operand2 & 0x000F);
uint8_t regShift = (operand2 & 0x0010) ? true : false;
uint8_t shiftType = (operand2 & 0x0060) >> 5;
uint32_t shiftDist;
#if defined(UNW_DEBUG)
const char * const shiftMnu[4] = { "LSL", "LSR", "ASR", "ROR" };
#endif
UnwPrintd2("r%d ", rm);
/* Get the shift distance */
if (regShift) {
uint8_t rs = (operand2 & 0x0F00) >> 8;
if (operand2 & 0x00800) {
UnwPrintd1("\nError: Bit should be zero\n");
return UNWIND_ILLEGAL_INSTR;
}
else if (rs == 15) {
UnwPrintd1("\nError: Cannot use R15 with register shift\n");
return UNWIND_ILLEGAL_INSTR;
}
/* Get shift distance */
shiftDist = state->regData[rs].v;
op2origin = state->regData[rs].o;
UnwPrintd7("%s r%d\t; r%d %s r%d %s", shiftMnu[shiftType], rs, rm, M_Origin2Str(state->regData[rm].o), rs, M_Origin2Str(state->regData[rs].o));
}
else {
shiftDist = (operand2 & 0x0F80) >> 7;
op2origin = REG_VAL_FROM_CONST;
if (shiftDist) {
UnwPrintd3("%s #%d", shiftMnu[shiftType], shiftDist);
}
UnwPrintd3("\t; r%d %s", rm, M_Origin2Str(state->regData[rm].o));
}
/* Apply the shift type to the source register */
switch(shiftType) {
case 0: /* logical left */
op2val = state->regData[rm].v << shiftDist;
break;
case 1: /* logical right */
if (!regShift && shiftDist == 0) {
shiftDist = 32;
}
op2val = state->regData[rm].v >> shiftDist;
break;
case 2: /* arithmetic right */
if (!regShift && shiftDist == 0) {
shiftDist = 32;
}
if (state->regData[rm].v & 0x80000000) {
/* Register shifts maybe greater than 32 */
if (shiftDist >= 32) {
op2val = 0xFFFFFFFF;
}
else {
op2val = state->regData[rm].v >> shiftDist;
op2val |= 0xFFFFFFFF << (32 - shiftDist);
}
}
else {
op2val = state->regData[rm].v >> shiftDist;
}
break;
case 3: /* rotate right */
if (!regShift && shiftDist == 0) {
/* Rotate right with extend.
* This uses the carry bit and so always has an
* untracked result.
*/
op2origin = REG_VAL_INVALID;
op2val = 0;
}
else {
/* Limit shift distance to 0-31 incase of register shift */
shiftDist &= 0x1F;
op2val = (state->regData[rm].v >> shiftDist) |
(state->regData[rm].v << (32 - shiftDist));
}
break;
default:
UnwPrintd2("\nError: Invalid shift type: %d\n", shiftType);
return UNWIND_FAILURE;
}
/* Decide the data origin */
if (M_IsOriginValid(op2origin) &&
M_IsOriginValid(state->regData[rm].o)) {
op2origin = state->regData[rm].o;
op2origin |= REG_VAL_ARITHMETIC;
}
else {
op2origin = REG_VAL_INVALID;
}
}
/* Propagate register validity */
switch(opcode) {
case 0: /* AND: Rd := Op1 AND Op2 */
case 1: /* EOR: Rd := Op1 EOR Op2 */
case 2: /* SUB: Rd:= Op1 - Op2 */
case 3: /* RSB: Rd:= Op2 - Op1 */
case 4: /* ADD: Rd:= Op1 + Op2 */
case 12: /* ORR: Rd:= Op1 OR Op2 */
case 14: /* BIC: Rd:= Op1 AND NOT Op2 */
if (!M_IsOriginValid(state->regData[rn].o) ||
!M_IsOriginValid(op2origin)) {
state->regData[rd].o = REG_VAL_INVALID;
}
else {
state->regData[rd].o = state->regData[rn].o;
state->regData[rd].o = (RegValOrigin)(state->regData[rd].o | op2origin);
}
break;
case 5: /* ADC: Rd:= Op1 + Op2 + C */
case 6: /* SBC: Rd:= Op1 - Op2 + C */
case 7: /* RSC: Rd:= Op2 - Op1 + C */
/* CPSR is not tracked */
state->regData[rd].o = REG_VAL_INVALID;
break;
case 8: /* TST: set condition codes on Op1 AND Op2 */
case 9: /* TEQ: set condition codes on Op1 EOR Op2 */
case 10: /* CMP: set condition codes on Op1 - Op2 */
case 11: /* CMN: set condition codes on Op1 + Op2 */
break;
case 13: /* MOV: Rd:= Op2 */
case 15: /* MVN: Rd:= NOT Op2 */
state->regData[rd].o = (RegValOrigin) op2origin;
break;
}
/* Account for pre-fetch by temporarily adjusting PC */
if (rn == 15) {
/* If the shift amount is specified in the instruction,
* the PC will be 8 bytes ahead. If a register is used
* to specify the shift amount the PC will be 12 bytes
* ahead.
*/
if (!I && (operand2 & 0x0010))
state->regData[rn].v += 12;
else
state->regData[rn].v += 8;
}
/* Compute values */
switch(opcode) {
case 0: /* AND: Rd := Op1 AND Op2 */
state->regData[rd].v = state->regData[rn].v & op2val;
break;
case 1: /* EOR: Rd := Op1 EOR Op2 */
state->regData[rd].v = state->regData[rn].v ^ op2val;
break;
case 2: /* SUB: Rd:= Op1 - Op2 */
state->regData[rd].v = state->regData[rn].v - op2val;
break;
case 3: /* RSB: Rd:= Op2 - Op1 */
state->regData[rd].v = op2val - state->regData[rn].v;
break;
case 4: /* ADD: Rd:= Op1 + Op2 */
state->regData[rd].v = state->regData[rn].v + op2val;
break;
case 5: /* ADC: Rd:= Op1 + Op2 + C */
case 6: /* SBC: Rd:= Op1 - Op2 + C */
case 7: /* RSC: Rd:= Op2 - Op1 + C */
case 8: /* TST: set condition codes on Op1 AND Op2 */
case 9: /* TEQ: set condition codes on Op1 EOR Op2 */
case 10: /* CMP: set condition codes on Op1 - Op2 */
case 11: /* CMN: set condition codes on Op1 + Op2 */
UnwPrintd1("\t; ????");
break;
case 12: /* ORR: Rd:= Op1 OR Op2 */
state->regData[rd].v = state->regData[rn].v | op2val;
break;
case 13: /* MOV: Rd:= Op2 */
state->regData[rd].v = op2val;
break;
case 14: /* BIC: Rd:= Op1 AND NOT Op2 */
state->regData[rd].v = state->regData[rn].v & (~op2val);
break;
case 15: /* MVN: Rd:= NOT Op2 */
state->regData[rd].v = ~op2val;
break;
}
/* Remove the prefetch offset from the PC */
if (rd != 15 && rn == 15) {
if (!I && (operand2 & 0x0010))
state->regData[rn].v -= 12;
else
state->regData[rn].v -= 8;
}
}
/* Block Data Transfer
* LDM, STM
*/
else if ((instr & 0xFE000000) == 0xE8000000) {
bool P = (instr & 0x01000000) ? true : false;
bool U = (instr & 0x00800000) ? true : false;
bool S = (instr & 0x00400000) ? true : false;
bool W = (instr & 0x00200000) ? true : false;
bool L = (instr & 0x00100000) ? true : false;
uint16_t baseReg = (instr & 0x000F0000) >> 16;
uint16_t regList = (instr & 0x0000FFFF);
uint32_t addr = state->regData[baseReg].v;
bool addrValid = M_IsOriginValid(state->regData[baseReg].o);
int8_t r;
#if defined(UNW_DEBUG)
/* Display the instruction */
if (L) {
UnwPrintd6("LDM%c%c r%d%s, {reglist}%s\n", P ? 'E' : 'F', U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
}
else {
UnwPrintd6("STM%c%c r%d%s, {reglist}%s\n", !P ? 'E' : 'F', !U ? 'D' : 'A', baseReg, W ? "!" : "", S ? "^" : "");
}
#endif
/* S indicates that banked registers (untracked) are used, unless
* this is a load including the PC when the S-bit indicates that
* that CPSR is loaded from SPSR (also untracked, but ignored).
*/
if (S && (!L || (regList & (0x01 << 15)) == 0)) {
UnwPrintd1("\nError:S-bit set requiring banked registers\n");
return UNWIND_FAILURE;
}
else if (baseReg == 15) {
UnwPrintd1("\nError: r15 used as base register\n");
return UNWIND_FAILURE;
}
else if (regList == 0) {
UnwPrintd1("\nError: Register list empty\n");
return UNWIND_FAILURE;
}
/* Check if ascending or descending.
* Registers are loaded/stored in order of address.
* i.e. r0 is at the lowest address, r15 at the highest.
*/
r = U ? 0 : 15;
do {
/* Check if the register is to be transferred */
if (regList & (0x01 << r)) {
if (P)
addr += U ? 4 : -4;
if (L) {
if (addrValid) {
if (!UnwMemReadRegister(state, addr, &state->regData[r])) {
return UNWIND_DREAD_W_FAIL;
}
/* Update the origin if read via the stack pointer */
if (M_IsOriginValid(state->regData[r].o) && baseReg == 13) {
state->regData[r].o = REG_VAL_FROM_STACK;
}
UnwPrintd5(" R%d = 0x%08x\t; r%d %s\n",r,state->regData[r].v,r, M_Origin2Str(state->regData[r].o));
}
else {
/* Invalidate the register as the base reg was invalid */
state->regData[r].o = REG_VAL_INVALID;
UnwPrintd2(" R%d = ???\n", r);
}
}
else {
if (addrValid) {
if (!UnwMemWriteRegister(state, state->regData[13].v, &state->regData[r])) {
return UNWIND_DWRITE_W_FAIL;
}
}
UnwPrintd2(" R%d = 0x%08x\n", r);
}
if (!P)
addr += U ? 4 : -4;
}
/* Check the next register */
r += U ? 1 : -1;
} while (r >= 0 && r <= 15);
/* Check the writeback bit */
if (W)
state->regData[baseReg].v = addr;
/* Check if the PC was loaded */
if (L && (regList & (0x01 << 15))) {
if (!M_IsOriginValid(state->regData[15].o)) {
/* Return address is not valid */
UnwPrintd1("PC popped with invalid address\n");
return UNWIND_FAILURE;
}
else {
/* Store the return address */
if (!UnwReportRetAddr(state, state->regData[15].v)) {
return UNWIND_TRUNCATED;
}
UnwPrintd2(" Return PC=0x%x", state->regData[15].v);
/* Determine the return mode */
if (state->regData[15].v & 0x1) {
/* Branching to THUMB */
return UnwStartThumb(state);
}
else {
/* Branch to ARM */
/* Account for the auto-increment which isn't needed */
state->regData[15].v -= 4;
}
}
}
}
else {
UnwPrintd1("????");
/* Unknown/undecoded. May alter some register, so invalidate file */
UnwInvalidateRegisterFile(state->regData);
}
UnwPrintd1("\n");
/* Should never hit the reset vector */
if (state->regData[15].v == 0) return UNWIND_RESET;
/* Check next address */
state->regData[15].v += 4;
/* Garbage collect the memory hash (used only for the stack) */
UnwMemHashGC(state);
t--;
if (t == 0)
return UNWIND_EXHAUSTED;
} while (!found);
return UNWIND_UNSUPPORTED;
}
#endif // __arm__ || __thumb__
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More