diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index ebc3311d9eda..88fc10a6d94e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1770,6 +1770,15 @@ */ //#define SDSUPPORT +/** + * SD CARD: SEARCH ORDER + * Order in which SD-Cards should be searched on the device, if there are more than one. + * (see SD-Cards definitions in your pins.h file) + * This setting makes marlin prioritize the cards if more than one is inserted. + * Change only if you prefer one SD-Card over the other (maybe because it's more accessible) + */ +//#define SD_SEARCH_ORDER { 0, 1, 2, 3 } + /** * SD CARD: SPI SPEED * diff --git a/Marlin/src/HAL/AVR/HAL_SPI.cpp b/Marlin/src/HAL/AVR/HAL_SPI.cpp index 31e589746cf2..b9719fe30028 100644 --- a/Marlin/src/HAL/AVR/HAL_SPI.cpp +++ b/Marlin/src/HAL/AVR/HAL_SPI.cpp @@ -34,21 +34,16 @@ #include "../../inc/MarlinConfig.h" void spiBegin() { + #if !PIN_EXISTS(SS) + #error "SS_PIN not defined!" + #endif OUT_WRITE(SS_PIN, HIGH); SET_OUTPUT(SCK_PIN); SET_INPUT(MISO_PIN); SET_OUTPUT(MOSI_PIN); - #if DISABLED(SOFTWARE_SPI) - // SS must be in output mode even it is not chip select - //SET_OUTPUT(SS_PIN); - // 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(1); - #endif + // set a default rate + spiInit(1); } #if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI) @@ -249,5 +244,4 @@ void spiBegin() { } #endif // SOFTWARE_SPI || FORCE_SOFT_SPI - #endif // __AVR__ diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp index c886f9c0b988..146896e987eb 100644 --- a/Marlin/src/HAL/STM32/HAL.cpp +++ b/Marlin/src/HAL/STM32/HAL.cpp @@ -63,8 +63,15 @@ uint16_t HAL_adc_result; void HAL_init() { FastIO_init(); - #if ENABLED(SDSUPPORT) && DISABLED(SDIO_SUPPORT) && (defined(SDSS) && SDSS != -1) - OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up + #if ENABLED(SDSUPPORT) && DISABLED(SDIO_SUPPORT) + // Temporary measure to prevent devices on the bus trying to become master. + // This will be done again when the SPI device is initialized. + for (uint8_t dev = 0; dev < NUM_SPI_DEVICES; dev++) { + extDigitalWrite(CS_OF_DEV(dev), HIGH); // Set CS HIGH (inactive) before other SPI users start. + pinMode(CS_OF_DEV(dev), OUTPUT); + if (IS_DEV_SD(dev) && SW_OF_SD(dev) != NC) // For an SD card with a real switch, set the pin as input + _SET_MODE(SW_OF_SD(dev), DLV_OF_SD(dev) == LOW ? INPUT_PULLUP : INPUT_PULLDOWN); // with the appropriate pull. + } #endif #if PIN_EXISTS(LED) @@ -72,11 +79,19 @@ void HAL_init() { #endif #if ENABLED(SRAM_EEPROM_EMULATION) + // Enable access to backup SRAM __HAL_RCC_PWR_CLK_ENABLE(); - HAL_PWR_EnableBkUpAccess(); // Enable access to backup SRAM + HAL_PWR_EnableBkUpAccess(); __HAL_RCC_BKPSRAM_CLK_ENABLE(); - LL_PWR_EnableBkUpRegulator(); // Enable backup regulator - while (!LL_PWR_IsActiveFlag_BRR()); // Wait until backup regulator is initialized + + // Enable backup regulator + LL_PWR_EnableBkUpRegulator(); + // Wait until backup regulator is initialized + while (!LL_PWR_IsActiveFlag_BRR()); + #endif + + #if HAS_TMC_SW_SERIAL + SoftwareSerial::setInterruptPriority(SWSERIAL_TIMER_IRQ_PRIO, 0); #endif SetTimerInterruptPriorities(); diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index 16dc7a453994..4cf38fbaaaa2 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -125,7 +125,7 @@ extern uint16_t HAL_adc_result; // Memory related #define __bss_end __bss_end__ -// Enable hooks into setup for HAL +// Enable hooks into setup for HAL void HAL_init(); // Clear reset reason diff --git a/Marlin/src/HAL/STM32/HAL_SPI.cpp b/Marlin/src/HAL/STM32/HAL_SPI.cpp index f947e6ef3272..b358e4a3d0bb 100644 --- a/Marlin/src/HAL/STM32/HAL_SPI.cpp +++ b/Marlin/src/HAL/STM32/HAL_SPI.cpp @@ -5,6 +5,7 @@ * Based on Sprinter and grbl. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm * Copyright (c) 2017 Victor Perez + * Copyright (c) 2019 Lino Barreca * * 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 @@ -24,197 +25,355 @@ #include "../../inc/MarlinConfig.h" -#include +#include //use this as helper for SPI peripheral Init configuration (temporary) + +#ifdef SPI_HAS_HW_CRC + // Add proper LL includes for board controller + #include +#endif + +#define SPI_TRANSFER_TIMEOUT 1000 +#define BUS_SPI_HANDLE(BUS_NUM) (&(spi[BUS_NUM] -> handle)) // ------------------------ // Public Variables // ------------------------ - -static SPISettings spiConfig; +static spi_t* spi[NUM_SPI_BUSES] = { NULL }; +static uint8_t last_dev[NUM_SPI_BUSES]; // ------------------------ // Public functions // ------------------------ -#if ENABLED(SOFTWARE_SPI) +bool spiInitialized(uint8_t bus_num) { + return spi[bus_num] != NULL; +} - // ------------------------ - // Software SPI - // ------------------------ +/** + * Initialize and configure SPI BUS for specified SPI speed + * + * @param bus_num Number of the spi bus + * @param spiRate Maximum speed of the bus in Mhz + * + * @return Nothing + */ +void spiBusInit(uint8_t bus_num, uint8_t spiRate) { + if (spiInitialized(bus_num)) spi_deinit(spi[bus_num]); // SPI already initialized (maybe at a different clock). De-init & re-init. + + spi[bus_num] = new spi_t(); + spi[bus_num] -> pin_sclk = digitalPinToPinName(SPI_BusConfig[bus_num][SPIBUS_CLCK]); + + uint32_t clock = spi_getClkFreq(spi[bus_num]); + + switch (spiRate) { + case SPI_FULL_SPEED: clock /= 2; break; // MAX Speed + case SPI_HALF_SPEED: clock /= 4; break; + case SPI_QUARTER_SPEED: clock /= 8; break; + case SPI_EIGHTH_SPEED: clock /= 16; break; + case SPI_SPEED_5: clock /= 128; break; + case SPI_SPEED_6: clock /= 256; break; // MIN Speed + default: + clock = SPI_SPEED_CLOCK_DEFAULT; // Default from the SPI library + } - #include "../shared/Delay.h" + spi[bus_num] -> pin_miso = digitalPinToPinName(SPI_BusConfig[bus_num][SPIBUS_MISO]); + spi[bus_num] -> pin_mosi = digitalPinToPinName(SPI_BusConfig[bus_num][SPIBUS_MOSI]); + spi[bus_num] -> pin_ssel = NC; // Chosen "manually" for each device transaction - void spiBegin(void) { - OUT_WRITE(SS_PIN, HIGH); - OUT_WRITE(SCK_PIN, HIGH); - SET_INPUT(MISO_PIN); - OUT_WRITE(MOSI_PIN, HIGH); - } + spi_init(spi[bus_num], clock, (spi_mode_e)SPI_BusConfig[bus_num][SPIBUS_MODE], SPI_BusConfig[bus_num][SPIBUS_BITO]); - static uint16_t delay_STM32_soft_spi; - - void spiInit(uint8_t spiRate) { - // Use datarates Marlin uses - switch (spiRate) { - case SPI_FULL_SPEED: delay_STM32_soft_spi = 125; break; // desired: 8,000,000 actual: ~1.1M - case SPI_HALF_SPEED: delay_STM32_soft_spi = 125; break; // desired: 4,000,000 actual: ~1.1M - case SPI_QUARTER_SPEED:delay_STM32_soft_spi = 250; break; // desired: 2,000,000 actual: ~890K - case SPI_EIGHTH_SPEED: delay_STM32_soft_spi = 500; break; // desired: 1,000,000 actual: ~590K - case SPI_SPEED_5: delay_STM32_soft_spi = 1000; break; // desired: 500,000 actual: ~360K - case SPI_SPEED_6: delay_STM32_soft_spi = 2000; break; // desired: 250,000 actual: ~210K - default: delay_STM32_soft_spi = 4000; break; // desired: 125,000 actual: ~123K - } - SPI.begin(); + char mess[50]; + sprintf(mess, PSTR("SPI %d Clock: %lu Hz"), bus_num, clock); + SERIAL_ECHOLN(mess); + last_dev[bus_num] = -1; +} + +uint8_t spiBusRec(uint8_t bus_num) { + #ifdef DUMP_SPI + SERIAL_CHAR('R'); + SERIAL_PRINT(bus_num, DEC); + SERIAL_CHAR(':'); + #endif + + uint8_t b = 0xFF; + + if (spiInitialized(bus_num)) { + HAL_SPI_Receive(BUS_SPI_HANDLE(bus_num), &b, 1, SPI_TRANSFER_TIMEOUT); + + #ifdef DUMP_SPI + SERIAL_PRINTLN(b, HEX); + #endif } - // Begin SPI transaction, set clock, bit order, data mode - void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { /* do nothing */ } + return b; +} + +void spiBusSend(uint8_t bus_num, uint8_t b) { + #ifdef DUMP_SPI + SERIAL_CHAR('S'); + SERIAL_PRINT(bus_num, DEC); + SERIAL_CHAR(':'); + #endif - uint8_t HAL_SPI_STM32_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3 - for (uint8_t bits = 8; bits--;) { - WRITE(SCK_PIN, LOW); - WRITE(MOSI_PIN, b & 0x80); + if (!spiInitialized(bus_num)) return; - DELAY_NS(delay_STM32_soft_spi); - WRITE(SCK_PIN, HIGH); - DELAY_NS(delay_STM32_soft_spi); + #ifdef DUMP_SPI + SERIAL_PRINTLN(b, HEX); + #endif + HAL_SPI_Transmit(BUS_SPI_HANDLE(bus_num), &b, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT); +} + +/** + * @brief Receive a number of bytes from the SPI bus to a buffer + * + * @param bus_num Bus number + * @param buf Pointer to starting address of buffer to write to. + * @param count Number of bytes to receive. + * + * @return Nothing + */ +void spiBusRead(uint8_t bus_num, uint8_t* buf, uint16_t count) { + #ifdef DUMP_SPI + SERIAL_CHAR('D'); + SERIAL_PRINT(bus_num, DEC); + SERIAL_CHAR(':'); + #endif + + if (count == 0 || !spiInitialized(bus_num)) return; + memset(buf, 0xFF, count); + + HAL_SPI_Receive(BUS_SPI_HANDLE(bus_num), buf, count, SPI_TRANSFER_TIMEOUT); + + #ifdef DUMP_SPI + for (uint16_t b = 0; b < count && b <= DUMP_SPI; b++) { + SERIAL_PRINT(buf[b], HEX); + serialprintPGM(b == DUMP_SPI ? PSTR("...") : PSTR(" ")); + } + SERIAL_EOL(); + #endif +} - b <<= 1; // little setup time - b |= (READ(MISO_PIN) != 0); +/** + * @brief Send a number of bytes to the SPI port + * + * @param bus_num Bus number + * @param buf Pointer to starting address of buffer to send. + * @param count Number of bytes to send. + * + * @return Nothing + */ +void spiBusWrite(uint8_t bus_num, const uint8_t* buf, uint16_t count) { + #ifdef DUMP_SPI + SERIAL_CHAR('U'); + SERIAL_PRINT(bus_num, DEC); + SERIAL_CHAR(':'); + #endif + + if (count == 0 || !spiInitialized(bus_num)) return; + + #ifdef DUMP_SPI + for (uint16_t b = 0; b < count && b <= DUMP_SPI; b++) { + SERIAL_PRINT(buf[b], HEX); + serialprintPGM(b == DUMP_SPI ? PSTR("...") : PSTR(" ")); } - DELAY_NS(125); - return b; - } + SERIAL_EOL(); + #endif - // Soft SPI receive byte - uint8_t spiRec() { - DISABLE_ISRS(); // No interrupts during byte receive - const uint8_t data = HAL_SPI_STM32_SpiTransfer_Mode_3(0xFF); - ENABLE_ISRS(); // Enable interrupts - return data; - } + HAL_SPI_Transmit(BUS_SPI_HANDLE(bus_num), (uint8_t*)buf, count, SPI_TRANSFER_TIMEOUT); +} - // Soft SPI read data - void spiRead(uint8_t *buf, uint16_t nbyte) { - for (uint16_t i = 0; i < nbyte; i++) - buf[i] = spiRec(); +void spiBegin() { + #if PIN_EXISTS(SS) + OUT_WRITE(SS_PIN, HIGH); + #endif +} + +// Convert Marlin speed enum to STM prescaler +uint32_t getPrescaler(uint8_t spiRate) { + switch (spiRate) { + case SPI_FULL_SPEED: return SPI_BAUDRATEPRESCALER_2; // MAX Speed + case SPI_HALF_SPEED: return SPI_BAUDRATEPRESCALER_4; + case SPI_QUARTER_SPEED: return SPI_BAUDRATEPRESCALER_8; + case SPI_EIGHTH_SPEED: return SPI_BAUDRATEPRESCALER_16; + case SPI_SPEED_5: return SPI_BAUDRATEPRESCALER_128; + case SPI_SPEED_6: return SPI_BAUDRATEPRESCALER_256; // MIN Speed + default: return -1; } +} - // Soft SPI send byte - void spiSend(uint8_t data) { - DISABLE_ISRS(); // No interrupts during byte send - HAL_SPI_STM32_SpiTransfer_Mode_3(data); // Don't care what is received - ENABLE_ISRS(); // Enable interrupts - } +/** + * @brief Configure the bus parameters to those required for the device + * @param dev_num Device number (identifies device and bus) + */ +void spiBusSet(uint8_t dev_num) { + if (last_dev[BUS_OF_DEV(dev_num)] == dev_num) return; + last_dev[BUS_OF_DEV(dev_num)] = dev_num; - // Soft SPI send block - void spiSendBlock(uint8_t token, const uint8_t *buf) { - spiSend(token); - for (uint16_t i = 0; i < 512; i++) - spiSend(buf[i]); - } + BUS_SPI_HANDLE(BUS_OF_DEV(dev_num))->Init.CLKPolarity = CPOL_OF_DEV(dev_num) == SPI_PLO ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH; + BUS_SPI_HANDLE(BUS_OF_DEV(dev_num))->Init.CLKPhase = CPHA_OF_DEV(dev_num) == SPI_LTS ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE; + BUS_SPI_HANDLE(BUS_OF_DEV(dev_num))->Init.FirstBit = BITO_OF_DEV(dev_num) == SPI_LSB ? SPI_FIRSTBIT_LSB : SPI_FIRSTBIT_MSB; + BUS_SPI_HANDLE(BUS_OF_DEV(dev_num))->Init.BaudRatePrescaler = getPrescaler( + (SPD_OF_DEV(dev_num) == NC) ? + SPI_BusConfig[BUS_OF_DEV(dev_num)][SPIBUS_DSPD] : // take default bus speed + SPD_OF_DEV(dev_num) // use device speed + ); -#else + HAL_SPI_Init(BUS_SPI_HANDLE(BUS_OF_DEV(dev_num))); +} - // ------------------------ - // Hardware SPI - // ------------------------ +// Device functions - /** - * VGPV SPI speed start and PCLK2/2, by default 108/2 = 54Mhz - */ +#ifdef SPI_HAS_HW_CRC /** - * @brief Begin SPI port setup - * - * @return Nothing - * - * @details Only configures SS pin since stm32duino creates and initialize the SPI object + * @brief Configures the parameters of the bus to the required ones for the device + * @param dev_num Device number (identifies device and bus) + * @return LL handle to the bus for additional configuration and start */ - void spiBegin() { - #if PIN_EXISTS(SS) - OUT_WRITE(SS_PIN, HIGH); - #endif + SPI_TypeDef* spiLLSetBus(uint8_t dev_num) { + last_dev[BUS_OF_DEV(dev_num)] = dev_num; + + SPI_TypeDef* hspi = BUS_SPI_HANDLE(BUS_OF_DEV(dev_num)) -> Instance; + + LL_SPI_Disable(hspi); + LL_SPI_SetClockPolarity(hspi, CPOL_OF_DEV(dev_num) == SPI_PLO ? LL_SPI_POLARITY_LOW : LL_SPI_POLARITY_HIGH); + LL_SPI_SetClockPhase(hspi, CPHA_OF_DEV(dev_num) == SPI_LTS ? LL_SPI_PHASE_1EDGE : LL_SPI_PHASE_2EDGE); + LL_SPI_SetTransferBitOrder(hspi, BITO_OF_DEV(dev_num) == SPI_LSB ? LL_SPI_LSB_FIRST : LL_SPI_MSB_FIRST); + //TODO: configure speed per device + + return hspi; } - // Configure SPI for specified SPI speed - void spiInit(uint8_t spiRate) { - // Use datarates Marlin uses - uint32_t clock; - switch (spiRate) { - case SPI_FULL_SPEED: clock = 20000000; break; // 13.9mhz=20000000 6.75mhz=10000000 3.38mhz=5000000 .833mhz=1000000 - 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 = 300000; break; - default: - clock = 4000000; // Default from the SPI library + uint16_t spiDevReadCRC16(uint8_t dev_num, uint16_t* buf, const uint16_t count) { + if (count == 0 || !spiInitialized(BUS_OF_DEV(dev_num))) return 0xFFFF; + + SPI_TypeDef * hspi = spiLLSetBus(dev_num); + LL_SPI_SetDataWidth(hspi, LL_SPI_DATAWIDTH_16BIT); + LL_SPI_SetCRCPolynomial(hspi, 0x1021); //0x1021 is the normal polynomial for CRC16-CCITT + LL_SPI_EnableCRC(hspi); //to clear CRC registers + LL_SPI_Enable(hspi); + digitalWrite(CS_OF_DEV(dev_num), LOW); //leave after LL_SPI_Enable + + bool send = true; + uint16_t remR = count; + + // data send + while (remR > 0) { + if (LL_SPI_IsActiveFlag_TXE(hspi) && send) { // if transmit buffer is empty and we need to send + LL_SPI_TransmitData16(hspi, 0xFFFF); // send + send = false; // and wait + } + + if (LL_SPI_IsActiveFlag_RXNE(hspi)) { // if receive buffer is not empty + buf[count - remR--] = __REV16(LL_SPI_ReceiveData16(hspi)); // receive + send = true; // and send next + } } - spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0); - #if ENABLED(CUSTOM_SPI_PINS) - SPI.setMISO(MISO_PIN); - SPI.setMOSI(MOSI_PIN); - SPI.setSCLK(SCK_PIN); - SPI.setSSEL(SS_PIN); - #endif + // CRC + while (LL_SPI_IsActiveFlag_BSY(hspi)); // wait for CRC to be ready + uint16_t hwCRC = (uint16_t)LL_SPI_GetRxCRC(hspi); // get CRC - SPI.begin(); - } + digitalWrite(CS_OF_DEV(dev_num), HIGH); + LL_SPI_Disable(hspi); + LL_SPI_DisableCRC(hspi); + LL_SPI_SetDataWidth(hspi, LL_SPI_DATAWIDTH_8BIT); + LL_SPI_Enable(hspi); - /** - * @brief Receives a single byte from the SPI port. - * - * @return Byte received - * - * @details - */ - uint8_t spiRec() { - uint8_t returnByte = SPI.transfer(0xFF); - return returnByte; + return hwCRC; // Return HW-computed CRC } - /** - * @brief Receive a number of bytes from the SPI port to a buffer - * - * @param buf Pointer to starting address of buffer to write to. - * @param nbyte Number of bytes to receive. - * @return Nothing - * - * @details Uses DMA - */ - void spiRead(uint8_t* buf, uint16_t nbyte) { - if (nbyte == 0) return; - memset(buf, 0xFF, nbyte); - SPI.transfer(buf, nbyte); - } + uint16_t spiDevWriteCRC16(uint8_t dev_num, const uint16_t* buf, const uint16_t count) { + if (count == 0 || !spiInitialized(BUS_OF_DEV(dev_num))) return 0xFFFF; - /** - * @brief Send a single byte on SPI port - * - * @param b Byte to send - * - * @details - */ - void spiSend(uint8_t b) { - SPI.transfer(b); - } + SPI_TypeDef * hspi = spiLLSetBus(dev_num); + LL_SPI_SetDataWidth(hspi, LL_SPI_DATAWIDTH_16BIT); + LL_SPI_SetCRCPolynomial(hspi, 0x1021); // 0x1021 is the normal polynomial for CRC16-CCITT + LL_SPI_EnableCRC(hspi); // to clear CRC registers + LL_SPI_Enable(hspi); + digitalWrite(CS_OF_DEV(dev_num), LOW); //leave after LL_SPI_Enable - /** - * @brief Write token and then write from 512 byte buffer to SPI (for SD card) - * - * @param buf Pointer with buffer start address - * @return Nothing - * - * @details Use DMA - */ - void spiSendBlock(uint8_t token, const uint8_t* buf) { - uint8_t rxBuf[512]; - SPI.transfer(token); - SPI.transfer((uint8_t*)buf, &rxBuf, 512); + uint16_t remT = count; + + while (remT > 0) + if (LL_SPI_IsActiveFlag_TXE(hspi)) // if transmit buffer is empty + LL_SPI_TransmitData16(hspi, __REV16(buf[count - remT--])); // send next + + // send complete. CRC's turn + //LL_SPI_SetCRCNext(hspi); // do not send it now. we need the reply externally + while (LL_SPI_IsActiveFlag_BSY(hspi) || !LL_SPI_IsActiveFlag_TXE(hspi)); // wait for empty send buffer + uint16_t hwCRC = LL_SPI_GetTxCRC(hspi); // get running CRC + + // bus reset + digitalWrite(CS_OF_DEV(dev_num), HIGH); + LL_SPI_Disable(hspi); + LL_SPI_DisableCRC(hspi); + LL_SPI_SetDataWidth(hspi, LL_SPI_DATAWIDTH_8BIT); + LL_SPI_Enable(hspi); + + return hwCRC; // Return HW-computed CRC } -#endif // SOFTWARE_SPI +#endif // SPI_HAS_HW_CRC + +/** + * @brief Receive a single byte from the SPI device. + * + * @param dev_num Device number (identifies device and bus) + * + * @return Byte received + */ +uint8_t spiDevRec(uint8_t dev_num) { + spiBusSet(dev_num); + digitalWrite(CS_OF_DEV(dev_num), LOW); + uint8_t b = spiBusRec(BUS_OF_DEV(dev_num)); + digitalWrite(CS_OF_DEV(dev_num), HIGH); + return b; +} + +/** + * @brief Send a single byte to a SPI device + * + * @param dev_num Device number (identifies device and bus) + * @param b Byte to send + */ +void spiDevSend(uint8_t dev_num, uint8_t b) { + spiBusSet(dev_num); + digitalWrite(CS_OF_DEV(dev_num), LOW); + spiBusSend(BUS_OF_DEV(dev_num), b); + digitalWrite(CS_OF_DEV(dev_num), HIGH); +} + +/** + * @brief Get a number of bytes from the SPI device into a buffer + * + * @param dev_num Device number (identifies device and bus) + * @param buf Pointer to starting address of buffer to write to. + * @param count Number of bytes to receive. + * + * @return Nothing + */ +void spiDevRead(uint8_t dev_num, uint8_t* buf, uint16_t count) { + spiBusSet(dev_num); + digitalWrite(CS_OF_DEV(dev_num), LOW); + spiBusRead(BUS_OF_DEV(dev_num), buf, count); + digitalWrite(CS_OF_DEV(dev_num), HIGH); +} + +/** + * @brief Write a number of bytes from the buffer to a SPI device + * + * @param dev_num Device number (identifies device and bus) + * @param buf Pointer to starting address of buffer to write to. + * @param count Number of bytes to receive. + * + * @return Nothing + */ +void spiDevWrite(uint8_t dev_num, const uint8_t* buf, uint16_t count) { + spiBusSet(dev_num); + digitalWrite(CS_OF_DEV(dev_num), LOW); + spiBusWrite(BUS_OF_DEV(dev_num), buf, count); + digitalWrite(CS_OF_DEV(dev_num), HIGH); +} #endif // ARDUINO_ARCH_STM32 && !STM32GENERIC diff --git a/Marlin/src/HAL/STM32F1/SPI.cpp b/Marlin/src/HAL/STM32F1/SPI.cpp index c0a35b88d1a2..1fb236823763 100644 --- a/Marlin/src/HAL/STM32F1/SPI.cpp +++ b/Marlin/src/HAL/STM32F1/SPI.cpp @@ -363,7 +363,7 @@ uint16_t SPIClass::transfer16(uint16_t data) const { /** * Roger Clark and Victor Perez, 2015 * Performs a DMA SPI transfer with at least a receive buffer. - * If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer. + * If a TX buffer is not provided, FF is sent over and over for the length of the transfer. * On exit TX buffer is not modified, and RX buffer cotains the received data. * Still in progress. */ diff --git a/Marlin/src/HAL/shared/HAL_SPI.h b/Marlin/src/HAL/shared/HAL_SPI.h index 59af5548064c..488c881e60e5 100644 --- a/Marlin/src/HAL/shared/HAL_SPI.h +++ b/Marlin/src/HAL/shared/HAL_SPI.h @@ -39,8 +39,6 @@ * 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. @@ -51,43 +49,125 @@ #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_SPEED_5 5 // Set SCK rate to 250 - 312 kHz +#define SPI_SPEED_6 6 // Set SCK rate to 125 - 156 kHz or lowest value possible for platform + +#define SPI_LSB 0 //LSB first +#define SPI_MSB 1 //MSB first +#define SPI_PLO 0 //Low polarity +#define SPI_PHI 1 //High polarity +#define SPI_LTS 0 //Latch then shift +#define SPI_STL 1 //Shift then latch + +//SPI device types +#define DEVTYPE_SD 0 +#define DEVTYPE_DRIVER 1 +#define DEVTYPE_DISPLAY 2 +#define DEVTYPE_SENSOR 3 +#define DEVTYPE_EEPROM 4 + +/** + * Index accessors + */ + +// SPI bus +#define SPIBUS_MOSI 0 +#define SPIBUS_MISO 1 +#define SPIBUS_CLCK 2 +#define SPIBUS_MODE 3 //default mode (calls to bus, not directed to a device. Temporary for SD card, will be removed) +#define SPIBUS_BITO 4 //default bit order (calls to bus, not directed to a device. Temporary for SD card, will be removed) +#define SPIBUS_DSPD 5 //default speed (calls to bus, not directed to a device. Temporary for SD card, will be removed) + +//Common SPI device properties +#define SPIDEV_TYPE 0 //device type +#define SPIDEV_BUS 1 //attached to bus +#define SPIDEV_CPOL 2 //polarity +#define SPIDEV_CPHA 3 //phase +#define SPIDEV_BITO 4 //bit order +#define SPIDEV_SPD 5 //speed +#define SPIDEV_CS 6 //selection + +//SPI device properties (by type) +#define SPIDEV_SW 7 //detection +#define SPIDEV_DLV 8 //level when detected +#define SPIDEV_DT 7 //driver type +#define SPIDEV_DI 8 //driver index + +//SPI Device Driver types +#define DRIVER_AXIS 0 +#define DRIVER_EXTRUDER 1 + +#define IS_DEV_SD(X) SPI_Devices[X][SPIDEV_TYPE] == DEVTYPE_SD +#define IS_DEV_EEPROM(X) SPI_Devices[X][SPIDEV_TYPE] == DEVTYPE_EEPROM +#define IS_DEV_DRIVER(X) SPI_Devices[X][SPIDEV_TYPE] == DEVTYPE_DRIVER + +#define BUS_OF_DEV(X) SPI_Devices[X][SPIDEV_BUS] +#define CS_OF_DEV(X) SPI_Devices[X][SPIDEV_CS] +#define CPOL_OF_DEV(X) SPI_Devices[X][SPIDEV_CPOL] +#define CPHA_OF_DEV(X) SPI_Devices[X][SPIDEV_CPHA] +#define BITO_OF_DEV(X) SPI_Devices[X][SPIDEV_BITO] +#define SPD_OF_DEV(X) SPI_Devices[X][SPIDEV_SPD] + +#define TYPE_OF_DRIVER(X) SPI_Devices[X][SPIDEV_DT] +#define AXIS_OF_DRIVER(X) SPI_Devices[X][SPIDEV_DI] + +//SD card +#define SW_OF_SD(X) SPI_Devices[X][SPIDEV_SW] +#define DLV_OF_SD(X) SPI_Devices[X][SPIDEV_DLV] + +//Driver +#define TYPE_OF_DRIVER(X) SPI_Devices[X][SPIDEV_DT] +#define IDX_OF_DRIVER(X) SPI_Devices[X][SPIDEV_DI] // -// Standard SPI functions +// Calls directed to the whole bus // -// Initialize SPI bus -void spiBegin(); +bool spiInitialized(uint8_t bus_num); + +// Initialize and configure SPI bus for specified clock speed and no CRC +void spiBusInit(uint8_t bus_num, uint8_t spiRate); -// Configure SPI for specified SPI speed -void spiInit(uint8_t spiRate); +// Write single byte to SPI bus, regardless of device +void spiBusSend(uint8_t bus_num, uint8_t b); -// Write single byte to SPI -void spiSend(uint8_t b); +// Read a single byte from SPI bus, regardless of device +uint8_t spiBusRec(uint8_t bus_num); -// Read single byte from SPI -uint8_t spiRec(); +// Read from SPI bus into buffer +void spiBusRead(uint8_t bus_num, uint8_t* buf, uint16_t count); + +// Write from buffer to SPI bus +void spiBusWrite(uint8_t bus_num, const uint8_t* buf, uint16_t count); + +// +// Calls directed to a device +// -// Read from SPI into buffer -void spiRead(uint8_t* buf, uint16_t nbyte); +// Write single byte to SPI device +void spiDevSend(uint8_t dev_num, uint8_t b); +// Read single byte from SPI device +uint8_t spiDevRec(uint8_t dev_num); -// Write token and then write from 512 byte buffer to SPI (for SD card) -void spiSendBlock(uint8_t token, const uint8_t* buf); +// Read from SPI device into buffer +void spiDevRead(uint8_t dev_num, uint8_t* buf, uint16_t count); +// Write from buffer to SPI device +void spiDevWrite(uint8_t dev_num, const uint8_t* buf, uint16_t count); -// Begin SPI transaction, set clock, bit order, data mode -void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode); +// Read from SPI device into buffer and return true if crc is OK +uint16_t spiDevReadCRC16(uint8_t dev_num, uint16_t* buf, uint16_t count); +// Write from buffer to SPI bus and returns HW calculated CRC16 on data +uint16_t spiDevWriteCRC16(uint8_t dev_num, const uint16_t* buf, uint16_t count); // // Extended SPI functions taking a channel number (Hardware SPI only) // // Write single byte to specified SPI channel -void spiSend(uint32_t chan, byte b); +void spiChnSend(uint32_t chan, byte b); // Write buffer to specified SPI channel -void spiSend(uint32_t chan, const uint8_t* buf, size_t n); +void spiChnSend(uint32_t chan, const uint8_t* buf, size_t n); // Read single byte from specified SPI channel -uint8_t spiRec(uint32_t chan); +uint8_t spiChnRec(uint32_t chan); diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index dfecd57749b0..c18ec80409af 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -2538,18 +2538,6 @@ #undef SOUND_MENU_ITEM // No buzzer menu item without a buzzer #endif -/** - * Make sure DOGLCD_SCK and DOGLCD_MOSI are defined. - */ -#if HAS_MARLINUI_U8GLIB - #ifndef DOGLCD_SCK - #define DOGLCD_SCK SCK_PIN - #endif - #ifndef DOGLCD_MOSI - #define DOGLCD_MOSI MOSI_PIN - #endif -#endif - /** * Z_HOMING_HEIGHT / Z_CLEARANCE_BETWEEN_PROBES */ diff --git a/Marlin/src/inc/MarlinConfig.h b/Marlin/src/inc/MarlinConfig.h index 2eafa2b4171f..8e1b652b664a 100644 --- a/Marlin/src/inc/MarlinConfig.h +++ b/Marlin/src/inc/MarlinConfig.h @@ -35,7 +35,6 @@ #ifndef __MARLIN_DEPS__ #include HAL_PATH(../HAL, timers.h) - #include HAL_PATH(../HAL, spi_pins.h) #endif #include "Conditionals_post.h" diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index eec9ff084464..414e2ad55f55 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2409,45 +2409,6 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal #error "LED_USER_PRESET_STARTUP is required for FYSETC_MINI_12864 2.x displays." #endif -/** - * Check existing CS pins against enabled TMC SPI drivers. - */ -#define INVALID_TMC_SPI(ST) (AXIS_HAS_SPI(ST) && !PIN_EXISTS(ST##_CS)) -#if INVALID_TMC_SPI(X) - #error "An SPI driven TMC driver on X requires X_CS_PIN." -#elif INVALID_TMC_SPI(X2) - #error "An SPI driven TMC driver on X2 requires X2_CS_PIN." -#elif INVALID_TMC_SPI(Y) - #error "An SPI driven TMC driver on Y requires Y_CS_PIN." -#elif INVALID_TMC_SPI(Y2) - #error "An SPI driven TMC driver on Y2 requires Y2_CS_PIN." -#elif INVALID_TMC_SPI(Z) - #error "An SPI driven TMC driver on Z requires Z_CS_PIN." -#elif INVALID_TMC_SPI(Z2) - #error "An SPI driven TMC driver on Z2 requires Z2_CS_PIN." -#elif INVALID_TMC_SPI(Z3) - #error "An SPI driven TMC driver on Z3 requires Z3_CS_PIN." -#elif INVALID_TMC_SPI(Z4) - #error "An SPI driven TMC driver on Z4 requires Z4_CS_PIN." -#elif INVALID_TMC_SPI(E0) - #error "An SPI driven TMC driver on E0 requires E0_CS_PIN." -#elif INVALID_TMC_SPI(E1) - #error "An SPI driven TMC driver on E1 requires E1_CS_PIN." -#elif INVALID_TMC_SPI(E2) - #error "An SPI driven TMC driver on E2 requires E2_CS_PIN." -#elif INVALID_TMC_SPI(E3) - #error "An SPI driven TMC driver on E3 requires E3_CS_PIN." -#elif INVALID_TMC_SPI(E4) - #error "An SPI driven TMC driver on E4 requires E4_CS_PIN." -#elif INVALID_TMC_SPI(E5) - #error "An SPI driven TMC driver on E5 requires E5_CS_PIN." -#elif INVALID_TMC_SPI(E6) - #error "An SPI driven TMC driver on E6 requires E6_CS_PIN." -#elif INVALID_TMC_SPI(E7) - #error "An SPI driven TMC driver on E7 requires E7_CS_PIN." -#endif -#undef INVALID_TMC_SPI - /** * Check existing RX/TX pins against enable TMC UART drivers. */ diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index c33581d132fe..47367681c5e4 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -42,11 +42,12 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E }; // ST = Stepper object letter // L = Label characters // AI = Axis Enum Index +// IX = SPI device index // SWHW = SW/SH UART selection #if ENABLED(TMC_USE_SW_SPI) - #define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK, ST##_CHAIN_POS) + #define __TMC_SPI_DEFINE(IC, ST, L, AI, IX) TMCMarlin stepper##ST(CS_OF_DEV(IX), float(ST##_RSENSE), SPI_BusConfig[BUS_OF_DEV(IX)][SPIBUS_MOSI], SPI_BusConfig[BUS_OF_DEV(IX)][SPIBUS_MISO], SPI_BusConfig[BUS_OF_DEV(IX)][SPIBUS_CLCK], ST##_CHAIN_POS) #else - #define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), ST##_CHAIN_POS) + #define __TMC_SPI_DEFINE(IC, ST, L, AI, IX) TMCMarlin stepper##ST(CS_OF_DEV(IX), float(ST##_RSENSE), ST##_CHAIN_POS) #endif #if ENABLED(TMC_SERIAL_MULTIPLEXER) @@ -56,68 +57,91 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E }; #endif #define TMC_UART_SW_DEFINE(IC, ST, L, AI) TMCMarlin stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, float(ST##_RSENSE), ST##_SLAVE_ADDRESS) -#define _TMC_SPI_DEFINE(IC, ST, AI) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI) -#define TMC_SPI_DEFINE(ST, AI) _TMC_SPI_DEFINE(ST##_DRIVER_TYPE, ST, AI##_AXIS) +#define _TMC_SPI_DEFINE(IC, ST, AI, IX) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI, IX) +#define TMC_SPI_DEFINE(ST, AI, IX) _TMC_SPI_DEFINE(ST##_DRIVER_TYPE, ST, AI##_AXIS, IX) #define _TMC_UART_DEFINE(SWHW, IC, ST, AI) TMC_UART_##SWHW##_DEFINE(IC, ST, TMC_##ST##_LABEL, AI) #define TMC_UART_DEFINE(SWHW, ST, AI) _TMC_UART_DEFINE(SWHW, ST##_DRIVER_TYPE, ST, AI##_AXIS) #if DISTINCT_E > 1 - #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E##AI) + #define TMC_SPI_DEFINE_E(AI, IX) TMC_SPI_DEFINE(E##AI, E##AI, IX) #define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E##AI) #else - #define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E) + #define TMC_SPI_DEFINE_E(AI, IX) TMC_SPI_DEFINE(E##AI, E, IX) #define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E) #endif // Stepper objects of TMC2130/TMC2160/TMC2660/TMC5130/TMC5160 steppers used +int findDriver(const int driverType, const int driverIndex) { + for (uint8_t i = 0; i < NUM_SPI_DEVICES; i++) + if (IS_DEV_DRIVER(i) && TYPE_OF_DRIVER(i) == driverType && AXIS_OF_DRIVER(i) == driverIndex) return i; + // TODO: add some message to warn user the config is wrong. + return -1; +} + #if AXIS_HAS_SPI(X) - TMC_SPI_DEFINE(X, X); + int xDev = findDriver(DRIVER_AXIS, 0); + TMC_SPI_DEFINE(X, X, xDev); #endif #if AXIS_HAS_SPI(X2) - TMC_SPI_DEFINE(X2, X); + int x2Dev = findDriver(DRIVER_AXIS, 10); + TMC_SPI_DEFINE(X2, X, x2Dev); #endif #if AXIS_HAS_SPI(Y) - TMC_SPI_DEFINE(Y, Y); + int yDev = findDriver(DRIVER_AXIS, 1); + TMC_SPI_DEFINE(Y, Y, yDev); #endif #if AXIS_HAS_SPI(Y2) - TMC_SPI_DEFINE(Y2, Y); + int y2Dev = findDriver(DRIVER_AXIS, 11); + TMC_SPI_DEFINE(Y2, Y, y2Dev); #endif #if AXIS_HAS_SPI(Z) - TMC_SPI_DEFINE(Z, Z); + int zDev = findDriver(DRIVER_AXIS, 2); + TMC_SPI_DEFINE(Z, Z, zDev); #endif #if AXIS_HAS_SPI(Z2) - TMC_SPI_DEFINE(Z2, Z); + int z2Dev = findDriver(DRIVER_AXIS, 12); + TMC_SPI_DEFINE(Z2, Z, z2Dev); #endif #if AXIS_HAS_SPI(Z3) - TMC_SPI_DEFINE(Z3, Z); + int z3Dev = findDriver(DRIVER_AXIS, 22); + TMC_SPI_DEFINE(Z3, Z, z3Dev); #endif #if AXIS_HAS_SPI(Z4) + int z4Dev = findDriver(DRIVER_AXIS, 32); TMC_SPI_DEFINE(Z4, Z); #endif #if AXIS_HAS_SPI(E0) - TMC_SPI_DEFINE_E(0); + int e0Dev = findDriver(DRIVER_EXTRUDER, 0); + TMC_SPI_DEFINE_E(0, e0Dev); #endif #if AXIS_HAS_SPI(E1) - TMC_SPI_DEFINE_E(1); + int e1Dev = findDriver(DRIVER_EXTRUDER, 1); + TMC_SPI_DEFINE_E(1, e1Dev); #endif #if AXIS_HAS_SPI(E2) - TMC_SPI_DEFINE_E(2); + int e2Dev = findDriver(DRIVER_EXTRUDER, 2); + TMC_SPI_DEFINE_E(2, e2Dev); #endif #if AXIS_HAS_SPI(E3) - TMC_SPI_DEFINE_E(3); + int e3Dev = findDriver(DRIVER_EXTRUDER, 3); + TMC_SPI_DEFINE_E(3, e3Dev); #endif #if AXIS_HAS_SPI(E4) - TMC_SPI_DEFINE_E(4); + int e4Dev = findDriver(DRIVER_EXTRUDER, 4); + TMC_SPI_DEFINE_E(4, e4Dev); #endif #if AXIS_HAS_SPI(E5) - TMC_SPI_DEFINE_E(5); + int e5Dev = findDriver(DRIVER_EXTRUDER, 5); + TMC_SPI_DEFINE_E(5, e5Dev); #endif #if AXIS_HAS_SPI(E6) - TMC_SPI_DEFINE_E(6); + int e6Dev = findDriver(DRIVER_EXTRUDER, 6); + TMC_SPI_DEFINE_E(6, e6Dev); #endif #if AXIS_HAS_SPI(E7) - TMC_SPI_DEFINE_E(7); + int e7Dev = findDriver(DRIVER_EXTRUDER, 7); + TMC_SPI_DEFINE_E(7, e7Dev); #endif #ifndef TMC_BAUD_RATE diff --git a/Marlin/src/pins/stm32/pins_BTT_SKR_PRO_V1_1.h b/Marlin/src/pins/stm32/pins_BTT_SKR_PRO_V1_1.h new file mode 100644 index 000000000000..ad86723a99be --- /dev/null +++ b/Marlin/src/pins/stm32/pins_BTT_SKR_PRO_V1_1.h @@ -0,0 +1,290 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 . + * + */ +#pragma once + +#ifndef TARGET_STM32F4 + #error "Oops! Select an STM32F4 board in 'Tools > Board.'" +#elif HOTENDS > 3 || E_STEPPERS > 3 + #error "BIGTREE SKR Pro V1.1 supports up to 3 hotends / E-steppers." +#endif + +#define BOARD_INFO_NAME "BIGTREE SKR Pro 1.1" // redefined? + +// Use one of these or SDCard-based Emulation will be used +//#define SRAM_EEPROM_EMULATION // Use BackSRAM-based EEPROM emulation +//#define FLASH_EEPROM_EMULATION // Use Flash-based EEPROM emulation + +// +// Servos +// +#define SERVO0_PIN PA1 + +// +// Limit Switches +// +#define X_MIN_PIN PB10 +#define X_MAX_PIN PE15 +#define Y_MIN_PIN PE12 +#define Y_MAX_PIN PE10 +#define Z_MIN_PIN PG8 +#define Z_MAX_PIN PG5 + +// +// Z Probe must be this pins +// +#ifndef Z_MIN_PROBE_PIN + #define Z_MIN_PROBE_PIN PA2 +#endif + +// +// Steppers +// +#define X_STEP_PIN PE9 +#define X_DIR_PIN PF1 +#define X_ENABLE_PIN PF2 + +#define Y_STEP_PIN PE11 +#define Y_DIR_PIN PE8 +#define Y_ENABLE_PIN PD7 + +#define Z_STEP_PIN PE13 +#define Z_DIR_PIN PC2 +#define Z_ENABLE_PIN PC0 + +#define E0_STEP_PIN PE14 +#define E0_DIR_PIN PA0 +#define E0_ENABLE_PIN PC3 + +#define E1_STEP_PIN PD15 +#define E1_DIR_PIN PE7 +#define E1_ENABLE_PIN PA3 + +#define E2_STEP_PIN PD13 +#define E2_DIR_PIN PG9 +#define E2_ENABLE_PIN PF0 + +#if HAS_TMC220x + /** + * TMC2208/TMC2209 stepper drivers + * + * Hardware serial communication ports. + * If undefined software serial is used according to the pins below + */ + //#define X_HARDWARE_SERIAL Serial + //#define X2_HARDWARE_SERIAL Serial1 + //#define Y_HARDWARE_SERIAL Serial1 + //#define Y2_HARDWARE_SERIAL Serial1 + //#define Z_HARDWARE_SERIAL Serial1 + //#define Z2_HARDWARE_SERIAL Serial1 + //#define E0_HARDWARE_SERIAL Serial1 + //#define E1_HARDWARE_SERIAL Serial1 + //#define E2_HARDWARE_SERIAL Serial1 + //#define E3_HARDWARE_SERIAL Serial1 + //#define E4_HARDWARE_SERIAL Serial1 + + // + // Software serial + // + #define X_SERIAL_TX_PIN PC13 + #define X_SERIAL_RX_PIN PC13 + + #define Y_SERIAL_TX_PIN PE3 + #define Y_SERIAL_RX_PIN PE3 + + #define Z_SERIAL_TX_PIN PE1 + #define Z_SERIAL_RX_PIN PE1 + + #define E0_SERIAL_TX_PIN PD4 + #define E0_SERIAL_RX_PIN PD4 + + #define E1_SERIAL_TX_PIN PD1 + #define E1_SERIAL_RX_PIN PD1 + + #define E2_SERIAL_TX_PIN PD6 + #define E2_SERIAL_RX_PIN PD6 + + // Reduce baud rate to improve software serial reliability + #define TMC_BAUD_RATE 19200 +#endif + +// +// Temperature Sensors +// +#define TEMP_0_PIN PF4 // T1 <-> E0 +#define TEMP_1_PIN PF5 // T2 <-> E1 +#define TEMP_2_PIN PF6 // T3 <-> E2 +#define TEMP_BED_PIN PF3 // T0 <-> Bed + +// +// Heaters / Fans +// +#define HEATER_0_PIN PB1 // Heater0 +#define HEATER_1_PIN PD14 // Heater1 +#define HEATER_2_PIN PB0 // Heater1 +#define HEATER_BED_PIN PD12 // Hotbed +#define FAN_PIN PC8 // Fan0 +#define FAN1_PIN PE5 // Fan1 +#define FAN2_PIN PE6 // Fan2 + +// +// SPI devices, buses and pins definition +// +#define NUM_SPI_BUSES 3 //number of SPI buses in the controller +#define SPI_HAS_HW_CRC //board supports hardware CRC + +const int SPI_BusConfig[NUM_SPI_BUSES][6] = { +// MOSI, MISO, SCK , Mode (def), Bit order (default) + {PB5 , PA6 , PA5 , SPI_MODE_3, SPI_MSB, SPI_HALF_SPEED}, //BUS0: only connected to onboard SD + {PB15, PB14, PB13, SPI_MODE_0, SPI_MSB, SPI_FULL_SPEED}, //BUS1: on EXT2 port + {PC12, PC11, PC10, SPI_MODE_0, SPI_MSB, SPI_FULL_SPEED} //BUS2: on SPI3 port (when not used by drivers) +}; + +#ifdef SD_DETECT_INVERTED + #define ExtSDLV LOW +#else + #define ExtSDLV HIGH +#endif + +const int SPI_Devices[][9] = { +// Device type BUS Polarity Phase Bit MAX Supported Selection Detect PIN Level when detected +// NR. Order Speed PIN (SD only) (SD only) + {DEVTYPE_SD , 0, SPI_PHI, SPI_STL, SPI_MSB, SPI_HALF_SPEED, PA4, PB11, LOW }, + {DEVTYPE_SD , 1, SPI_PLO, SPI_LTS, SPI_MSB, SPI_FULL_SPEED, PB12, PF12, ExtSDLV}, + {DEVTYPE_SD , 2, SPI_PLO, SPI_LTS, SPI_MSB, SPI_FULL_SPEED, PA15, NC, NC }, //optional external SD on SPI3 +#if HAS_SPI_LCD + {DEVTYPE_DISPLAY, 1, SPI_PLO, SPI_LTS, SPI_MSB, SPI_FULL_SPEED, PD11, NC, NC }, +#endif +//Drivers on this board are hard-wired. +//Users can't change the CS so we disallow the user-redefinition of the CS_PIN + +// Device type BUS Polarity Phase Bit MAX Supported Selection Type, Index (for type) +// NR. Order Speed PIN (Driver only) (Driver only) +#if AXIS_HAS_SPI(X) //NC = not change: use the default for the bus + {DEVTYPE_DRIVER , 2, NC, NC, NC, SPI_FULL_SPEED, PA15, DRIVER_AXIS , 0}, //Index 0 is X +#endif +#if AXIS_HAS_SPI(Y) + {DEVTYPE_DRIVER , 2, NC, NC, NC, SPI_FULL_SPEED, PB8, DRIVER_AXIS , 1}, //Index 1 is Y +#endif +#if AXIS_HAS_SPI(Z) + {DEVTYPE_DRIVER , 2, NC, NC, NC, SPI_FULL_SPEED, PB9, DRIVER_AXIS , 2}, //Index 2 is Z +#endif +#if AXIS_HAS_SPI(E0) + {DEVTYPE_DRIVER , 2, NC, NC, NC, SPI_FULL_SPEED, PB3, DRIVER_EXTRUDER, 0}, //E0 +#endif +#if AXIS_HAS_SPI(E1) + {DEVTYPE_DRIVER , 2, NC, NC, NC, SPI_FULL_SPEED, PG15, DRIVER_EXTRUDER, 1}, //E1 +#endif +#if AXIS_HAS_SPI(E2) + {DEVTYPE_DRIVER , 2, NC, NC, NC, SPI_FULL_SPEED, PG12, DRIVER_EXTRUDER, 2}, //E2 +#endif + {DEVTYPE_EEPROM , 2, NC, NC, NC, SPI_FULL_SPEED, PA15, NC, NC} //optional external EEPROM on SPI3 +}; + +#define NUM_SPI_DEVICES COUNT(SPI_Devices) + +#ifndef SD_SEARCH_ORDER + #define SD_SEARCH_ORDER { 1, 0, 2 } +#endif + +// +// Misc. Functions +// + +/** + * _____ _____ + * NC | · · | GND 5V | · · | GND + * RESET | · · | PF12(SD_DETECT) (LCD_D7) PG7 | · · | PG6 (LCD_D6) + * (MOSI)PB15 | · · | PF11(BTN_EN2) (LCD_D5) PG3 | · · | PG2 (LCD_D4) + * (SD_SS)PB12 | · · | PG10(BTN_EN1) (LCD_RS) PD10 | · · | PD11 (LCD_EN) + * (SCK)PB13 | · · | PB14(MISO) (BTN_ENC) PA8 | · · | PG4 (BEEPER) + *  ̄ ̄  ̄ ̄ + * EXP2 EXP1 + */ + +// +// LCDs and Controllers +// +#if HAS_SPI_LCD + #define BEEPER_PIN PG4 + #define BTN_ENC PA8 + + #if ENABLED(CR10_STOCKDISPLAY) + #define LCD_PINS_RS PG6 + + #define BTN_EN1 PD11 + #define BTN_EN2 PG2 + + #define LCD_PINS_ENABLE PG7 + #define LCD_PINS_D4 PG3 + + // CR10_Stock Display needs a different delay setting on SKR PRO v1.1, so undef it here. + // It will be defined again at the #HAS_GRAPHICAL_LCD section below. + #undef ST7920_DELAY_1 + #undef ST7920_DELAY_2 + #undef ST7920_DELAY_3 + + #else + + #define LCD_PINS_RS PD10 + + #define BTN_EN1 PG10 + #define BTN_EN2 PF11 + + #define LCD_PINS_ENABLE PD11 + #define LCD_PINS_D4 PG2 + + #if ENABLED(FYSETC_MINI_12864) + #define DOGLCD_CS PD11 + #define DOGLCD_A0 PD10 + //#define LCD_BACKLIGHT_PIN -1 + #define LCD_RESET_PIN PG2 // Must be high or open for LCD to operate normally. + #if EITHER(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0) + #ifndef RGB_LED_R_PIN + #define RGB_LED_R_PIN PG3 + #endif + #ifndef RGB_LED_G_PIN + #define RGB_LED_G_PIN PG6 + #endif + #ifndef RGB_LED_B_PIN + #define RGB_LED_B_PIN PG7 + #endif + #elif ENABLED(FYSETC_MINI_12864_2_1) + #define NEOPIXEL_PIN PG3 + #endif + #endif // !FYSETC_MINI_12864 + + #if ENABLED(ULTIPANEL) + #define LCD_PINS_D5 PG3 + #define LCD_PINS_D6 PG6 + #define LCD_PINS_D7 PG7 + #endif + + #endif + + // Alter timing for graphical display + #if HAS_GRAPHICAL_LCD + #define BOARD_ST7920_DELAY_1 DELAY_NS(96) + #define BOARD_ST7920_DELAY_2 DELAY_NS(48) + #define BOARD_ST7920_DELAY_3 DELAY_NS(600) + #endif + +#endif // HAS_SPI_LCD diff --git a/Marlin/src/sd/Sd2Card.cpp b/Marlin/src/sd/Sd2Card.cpp index 491c0692c72f..5389fb73cee4 100644 --- a/Marlin/src/sd/Sd2Card.cpp +++ b/Marlin/src/sd/Sd2Card.cpp @@ -34,16 +34,16 @@ /* Enable FAST CRC computations - You can trade speed for FLASH space if * needed by disabling the following define */ -#define FAST_CRC 1 +#define FAST_CRC #include "Sd2Card.h" #include "../MarlinCore.h" -#if ENABLED(SD_CHECK_AND_RETRY) - static bool crcSupported = true; +static bool crcSupported = false; - #ifdef FAST_CRC +#if ENABLED(SD_CHECK_AND_RETRY) + #if ENABLED(FAST_CRC) static const uint8_t crctab7[] PROGMEM = { 0x00,0x09,0x12,0x1B,0x24,0x2D,0x36,0x3F,0x48,0x41,0x5A,0x53,0x6C,0x65,0x7E,0x77, 0x19,0x10,0x0B,0x02,0x3D,0x34,0x2F,0x26,0x51,0x58,0x43,0x4A,0x75,0x7C,0x67,0x6E, @@ -89,42 +89,86 @@ // Send command and return error code. Return zero for OK uint8_t Sd2Card::cardCommand(const uint8_t cmd, const uint32_t arg) { - // Select card - chipSelect(); - // Wait up to 300 ms if busy waitNotBusy(SD_WRITE_TIMEOUT); - uint8_t *pa = (uint8_t *)(&arg); - - #if ENABLED(SD_CHECK_AND_RETRY) + uint8_t + crcErrors = 0, //crc error counter + reply, //expected reply format + *pa = (uint8_t *)(&arg), //pointer to arguments + d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] }; //Message: Command + Parameters + CRC(=0, set below) + + // Set crc at end of message + switch (cmd) { + case CMD0: d[5] = 0x95; break; //with arg zero + case CMD8: d[5] = 0x87; break; //with arg 0X1AA + default: + #if ENABLED(SD_CHECK_AND_RETRY) + d[5] = CRC7(d, 5); + #endif + break; + } - // Form message - uint8_t d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] }; + switch (cmd) { + case CMD8 : reply = R7; break; //R7 = R1 + voltage specifications (4 bytes) (R7 is read and parsed outside) + //case CMD38: wait is handled externally + //case CMD28: not handled at the moment + //case CMD29: not handled at the moment + case CMD12 : reply = R1b; break; //R1b = R1 + busy (any number of bytes until 0xFF) + case CMD13 : reply = R2; break; //R2 = R1 + status (1 byte) status is checked outside + case CMD58 : + case ACMD41: + reply = R3; break; //R3 = R1 + OCR/CSS (4 bytes) OCR/CSS is read outside + default : reply = R1; break; + } - // Add crc - d[5] = CRC7(d, 5); + do { + #ifdef TRACE_SD + SERIAL_ECHO("CMD"); + SERIAL_PRINTLN(cmd, DEC); + #endif - // Send message - LOOP_L_N(k, 6) spiSend(d[k]); + spiDevWrite(dev_num, d, 6); // Send message + + // Specs: "Wait for response at most 16 clock cycles" (= 2 bytes) + uint8_t i = 0; + do + status_ = spiDevRec(dev_num); + while ((status_ == 0xff) && (i++ < 3)); //wait 3 bytes, just to be sure + //Here status_ contains R1 + + //check if R1 has crc error. + if (status_ & 0b1000) { + #ifdef TRACE_SD + SERIAL_ECHOLN("CRC error from card. Retrying."); + #endif + crcErrors++; + } else + break; + } while (crcErrors > 0 && crcErrors < 3); //if we had a CRC error retry at most three times - #else - // Send command - spiSend(cmd | 0x40); + //TODO, if needed: add extra response parsing here - // Send argument - for (int8_t i = 3; i >= 0; i--) spiSend(pa[i]); + //discard command response if not needed + if (reply == R1b) { + #ifdef TRACE_SD + SERIAL_ECHOLN("discarding until 0xFF."); + #endif + while (spiDevRec(dev_num) != 0xFF); //undefined wait: loop until 0xFF received + } - // Send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA - spiSend(cmd == CMD0 ? 0X95 : 0X87); - #endif + return status_; +} - // Skip stuff byte for stop read - if (cmd == CMD12) spiRec(); +bool Sd2Card::anyInserted() { + for (uint8_t dev = 0; dev < NUM_SPI_DEVICES; dev++) + if (isInserted(dev)) return true; + return false; //not found.. +} - // Wait for response - for (uint8_t i = 0; ((status_ = spiRec()) & 0x80) && i != 0xFF; i++) { /* Intentionally left empty */ } - return status_; +bool Sd2Card::isInserted(const uint8_t dev_num) { + return (IS_DEV_SD(dev_num) && (SPI_Devices[dev_num][SPIDEV_SW] == NC) + || digitalRead(SPI_Devices[dev_num][SPIDEV_SW]) == SPI_Devices[dev_num][SPIDEV_DLV]); } /** @@ -155,16 +199,6 @@ uint32_t Sd2Card::cardSize() { } } -void Sd2Card::chipDeselect() { - extDigitalWrite(chipSelectPin_, HIGH); - spiSend(0xFF); // Ensure MISO goes high impedance -} - -void Sd2Card::chipSelect() { - spiInit(spiRate_); - extDigitalWrite(chipSelectPin_, LOW); -} - /** * Erase a range of blocks. * @@ -182,7 +216,7 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { if (ENABLED(SDCARD_READONLY)) return false; csd_t csd; - if (!readCSD(&csd)) goto FAIL; + if (!readCSD(&csd)) return false; // check for single block erase if (!csd.v1.erase_blk_en) { @@ -191,23 +225,20 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { // error card can't erase specified area error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); - goto FAIL; + return false; } } if (type_ != SD_CARD_TYPE_SDHC) { firstBlock <<= 9; lastBlock <<= 9; } if (cardCommand(CMD32, firstBlock) || cardCommand(CMD33, lastBlock) || cardCommand(CMD38, 0)) { error(SD_CARD_ERROR_ERASE); - goto FAIL; + return false; } if (!waitNotBusy(SD_ERASE_TIMEOUT)) { error(SD_CARD_ERROR_ERASE_TIMEOUT); - goto FAIL; + return false; } - chipDeselect(); + return true; - FAIL: - chipDeselect(); - return false; } /** @@ -225,12 +256,13 @@ bool Sd2Card::eraseSingleBlockEnable() { * Initialize an SD flash memory card. * * \param[in] sckRateID SPI clock rate selector. See setSckRate(). - * \param[in] chipSelectPin SD chip select pin number. * * \return true for success, false for failure. * The reason for failure can be determined by calling errorCode() and errorData(). */ bool Sd2Card::init(const uint8_t sckRateID, const pin_t chipSelectPin) { + if (dev_num == -1) return false; + #if IS_TEENSY_35_36 || IS_TEENSY_40_41 chipSelectPin_ = BUILTIN_SDCARD; const uint8_t ret = SDHC_CardInit(); @@ -239,7 +271,6 @@ bool Sd2Card::init(const uint8_t sckRateID, const pin_t chipSelectPin) { #endif errorCode_ = type_ = 0; - chipSelectPin_ = chipSelectPin; // 16-bit init start time allows over a minute const millis_t init_timeout = millis() + SD_INIT_TIMEOUT; uint32_t arg; @@ -253,35 +284,36 @@ bool Sd2Card::init(const uint8_t sckRateID, const pin_t chipSelectPin) { WRITE(DOGLCD_CS, HIGH); } #else - extDigitalWrite(chipSelectPin_, HIGH); // For some CPUs pinMode can write the wrong data so init desired data value first - pinMode(chipSelectPin_, OUTPUT); // Solution for #8746 by @benlye + // Set SCK rate for initialization commands + spiBusInit(BUS_OF_DEV(dev_num), SPI_SD_INIT_RATE); + extDigitalWrite(CS_OF_DEV(dev_num), HIGH); // For some CPUs pinMode can write the wrong data so init desired data value first + pinMode(CS_OF_DEV(dev_num), OUTPUT); // Solution for #8746 by @benlye #endif - spiBegin(); - // Set SCK rate for initialization commands - spiRate_ = SPI_SD_INIT_RATE; - spiInit(spiRate_); + // Set pin modes + //spiBegin(BUS_OF_DEV(dev_num)); // Must supply min of 74 clock cycles with CS high. - LOOP_L_N(i, 10) spiSend(0xFF); + LOOP_L_N(i, 10) spiBusSend(BUS_OF_DEV(dev_num), 0xFF); //Send to bus, not to device (to not alter CS) watchdog_refresh(); // In case init takes too long - // Command to go idle in SPI mode - while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { + // CMD0: Command to go idle in SPI mode + while (cardCommand(CMD0, 0) != R1_IDLE_STATE) { if (ELAPSED(millis(), init_timeout)) { error(SD_CARD_ERROR_CMD0); goto FAIL; } } + //CMD59: Enable CRC check #if ENABLED(SD_CHECK_AND_RETRY) crcSupported = (cardCommand(CMD59, 1) == R1_IDLE_STATE); #endif watchdog_refresh(); // In case init takes too long - // check SD version + //CMD8: Check SD version for (;;) { if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) { type(SD_CARD_TYPE_SD1); @@ -289,7 +321,7 @@ bool Sd2Card::init(const uint8_t sckRateID, const pin_t chipSelectPin) { } // Get the last byte of r7 response - LOOP_L_N(i, 4) status_ = spiRec(); + LOOP_L_N(i, 4) status_ = spiDevRec(dev_num); if (status_ == 0xAA) { type(SD_CARD_TYPE_SD2); break; @@ -318,16 +350,14 @@ bool Sd2Card::init(const uint8_t sckRateID, const pin_t chipSelectPin) { error(SD_CARD_ERROR_CMD58); goto FAIL; } - if ((spiRec() & 0xC0) == 0xC0) type(SD_CARD_TYPE_SDHC); + if ((spiDevRec(dev_num) & 0xC0) == 0xC0) type(SD_CARD_TYPE_SDHC); // Discard rest of ocr - contains allowed voltage range - LOOP_L_N(i, 3) spiRec(); + LOOP_L_N(i, 3) spiDevRec(dev_num); } - chipDeselect(); return setSckRate(sckRateID); FAIL: - chipDeselect(); return false; } @@ -353,7 +383,6 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { else if (readData(dst, 512)) return true; - chipDeselect(); if (!--retryCnt) break; cardCommand(CMD12, 0); // Try sending a stop command, ignore the result. @@ -363,7 +392,6 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { #else if (cardCommand(CMD17, blockNumber)) { error(SD_CARD_ERROR_CMD17); - chipDeselect(); return false; } else @@ -379,56 +407,59 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { * \return true for success, false for failure. */ bool Sd2Card::readData(uint8_t* dst) { - chipSelect(); return readData(dst, 512); } -#if ENABLED(SD_CHECK_AND_RETRY) - #ifdef FAST_CRC - static const uint16_t crctab16[] PROGMEM = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 - }; +#if ENABLED(SD_CHECK_AND_RETRY) && !defined(SPI_HAS_HW_CRC) + #if ENABLED(FAST_CRC) + + static const uint16_t crctab16[] PROGMEM = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 + }; + // faster CRC-CCITT // uses the x^16,x^12,x^5,x^1 polynomial. - static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { - uint16_t crc = 0; - for (size_t i = 0; i < n; i++) { - crc = pgm_read_word(&crctab16[(crc >> 8 ^ data[i]) & 0xFF]) ^ (crc << 8); + static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { + uint16_t crc = 0; + for (size_t i = 0; i < n; i++) + crc = pgm_read_word(&crctab16[(crc >> 8 ^ data[i]) & 0xFF]) ^ (crc << 8); + + return crc; } - return crc; - } + #else + // slower CRC-CCITT // uses the x^16,x^12,x^5,x^1 polynomial. static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { @@ -442,14 +473,15 @@ bool Sd2Card::readData(uint8_t* dst) { } return crc; } + #endif -#endif // SD_CHECK_AND_RETRY +#endif // !SPI_HAS_HW_CRC && SD_CHECK_AND_RETRY bool Sd2Card::readData(uint8_t* dst, const uint16_t count) { bool success = false; const millis_t read_timeout = millis() + SD_READ_TIMEOUT; - while ((status_ = spiRec()) == 0xFF) { // Wait for start block token + while ((status_ = spiDevRec(dev_num)) == 0xFF) { // Wait for start block token if (ELAPSED(millis(), read_timeout)) { error(SD_CARD_ERROR_READ_TIMEOUT); goto FAIL; @@ -457,22 +489,28 @@ bool Sd2Card::readData(uint8_t* dst, const uint16_t count) { } if (status_ == DATA_START_BLOCK) { - spiRead(dst, count); // Transfer data + uint16_t expCrc; + + #ifdef SPI_HAS_HW_CRC + expCrc = spiDevReadCRC16(dev_num, (uint16_t*)dst, count/2); + #else + spiDevRead(dev_num, dst, count); + #if ENABLED(SD_CHECK_AND_RETRY) + expCrc = crcSupported ? CRC_CCITT(dst, count) : 0xFFFF; + #endif + #endif + + const uint16_t recvCrc = (spiDevRec(dev_num) << 8) | spiDevRec(dev_num); //read bytes from bus anyway + success = (!crcSupported) || expCrc == recvCrc; - const uint16_t recvCrc = (spiRec() << 8) | spiRec(); #if ENABLED(SD_CHECK_AND_RETRY) - success = !crcSupported || recvCrc == CRC_CCITT(dst, count); if (!success) error(SD_CARD_ERROR_READ_CRC); - #else - success = true; - UNUSED(recvCrc); #endif } else error(SD_CARD_ERROR_READ); FAIL: - chipDeselect(); return success; } @@ -481,7 +519,6 @@ bool Sd2Card::readRegister(const uint8_t cmd, void* buf) { uint8_t* dst = reinterpret_cast(buf); if (cardCommand(cmd, 0)) { error(SD_CARD_ERROR_READ_REG); - chipDeselect(); return false; } return readData(dst, 16); @@ -502,7 +539,6 @@ bool Sd2Card::readStart(uint32_t blockNumber) { const bool success = !cardCommand(CMD18, blockNumber); if (!success) error(SD_CARD_ERROR_CMD18); - chipDeselect(); return success; } @@ -512,10 +548,8 @@ bool Sd2Card::readStart(uint32_t blockNumber) { * \return true for success, false for failure. */ bool Sd2Card::readStop() { - chipSelect(); const bool success = !cardCommand(CMD12, 0); if (!success) error(SD_CARD_ERROR_CMD12); - chipDeselect(); return success; } @@ -524,16 +558,13 @@ bool Sd2Card::readStop() { * * \param[in] sckRateID A value in the range [0, 6]. * - * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum - * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 - * for \a scsRateID = 6. - * * \return The value one, true, is returned for success and the value zero, * false, is returned for an invalid value of \a sckRateID. */ bool Sd2Card::setSckRate(const uint8_t sckRateID) { const bool success = (sckRateID <= 6); - if (success) spiRate_ = sckRateID; else error(SD_CARD_ERROR_SCK_RATE); + if (success) spiBusInit(BUS_OF_DEV(dev_num), sckRateID); else error(SD_CARD_ERROR_SCK_RATE); + return success; } @@ -544,7 +575,7 @@ bool Sd2Card::setSckRate(const uint8_t sckRateID) { */ bool Sd2Card::waitNotBusy(const millis_t timeout_ms) { const millis_t wait_timeout = millis() + timeout_ms; - while (spiRec() != 0xFF) if (ELAPSED(millis(), wait_timeout)) return false; + while (spiDevRec(dev_num) != 0xFF) if (ELAPSED(millis(), wait_timeout)) return false; return true; } @@ -566,8 +597,8 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card if (!cardCommand(CMD24, blockNumber)) { if (writeData(DATA_START_BLOCK, src)) { - if (waitNotBusy(SD_WRITE_TIMEOUT)) { // Wait for flashing to complete - success = !(cardCommand(CMD13, 0) || spiRec()); // Response is r2 so get and check two bytes for nonzero + if (waitNotBusy(SD_WRITE_TIMEOUT)) { // Wait for flashing to complete + success = !(cardCommand(CMD13, 0) || spiDevRec(dev_num)); // Response is r2 so get and check two bytes for nonzero if (!success) error(SD_CARD_ERROR_WRITE_PROGRAMMING); } else @@ -576,8 +607,6 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { } else error(SD_CARD_ERROR_CMD24); - - chipDeselect(); return success; } @@ -590,13 +619,11 @@ bool Sd2Card::writeData(const uint8_t* src) { if (ENABLED(SDCARD_READONLY)) return false; bool success = true; - chipSelect(); // Wait for previous write to finish if (!waitNotBusy(SD_WRITE_TIMEOUT) || !writeData(WRITE_MULTIPLE_TOKEN, src)) { error(SD_CARD_ERROR_WRITE_MULTIPLE); success = false; } - chipDeselect(); return success; } @@ -604,18 +631,36 @@ bool Sd2Card::writeData(const uint8_t* src) { bool Sd2Card::writeData(const uint8_t token, const uint8_t* src) { if (ENABLED(SDCARD_READONLY)) return false; - const uint16_t crc = TERN(SD_CHECK_AND_RETRY, CRC_CCITT(src, 512), 0xFFFF); - spiSendBlock(token, src); - spiSend(crc >> 8); - spiSend(crc & 0xFF); + spiDevSend(dev_num, token); // Token isn't included in CRC - status_ = spiRec(); - if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { - error(SD_CARD_ERROR_WRITE); - chipDeselect(); - return false; - } - return true; + uint16_t crc = ( + #if DISABLED(SD_CHECK_AND_RETRY) + 0xFFFF + #elif defined(SPI_HAS_HW_CRC) + spiDevWriteCRC16(dev_num, (uint16_t*)src, 256) + #else + CRC_CCITT(src, 512) + #endif + ); + + #if DISABLED(SD_CHECK_AND_RETRY) || !defined(SPI_HAS_HW_CRC) + spiDevWrite(dev_num, src, 512); + #endif + + spiDevSend(dev_num, crc >> 8); + spiDevSend(dev_num, crc & 0xFF); + + // Wait for reply. consider only bit 4-0 + millis_t wait_timeout = millis() + SD_WRITE_TIMEOUT; + while ((status_ = (spiDevRec(dev_num) & DATA_RES_MASK)) == DATA_RES_MASK) + if (ELAPSED(millis(), wait_timeout)) goto error; + + if (status_ == DATA_RES_ACCEPTED) + return true; + +error: + error(SD_CARD_ERROR_WRITE); + return false; } /** @@ -641,7 +686,6 @@ bool Sd2Card::writeStart(uint32_t blockNumber, const uint32_t eraseCount) { else error(SD_CARD_ERROR_ACMD23); - chipDeselect(); return success; } @@ -654,16 +698,14 @@ bool Sd2Card::writeStop() { if (ENABLED(SDCARD_READONLY)) return false; bool success = false; - chipSelect(); if (waitNotBusy(SD_WRITE_TIMEOUT)) { - spiSend(STOP_TRAN_TOKEN); + spiDevSend(dev_num, STOP_TRAN_TOKEN); success = waitNotBusy(SD_WRITE_TIMEOUT); } else error(SD_CARD_ERROR_STOP_TRAN); - chipDeselect(); return success; } -#endif // SDSUPPORT +#endif // SDSUPPORT && !USB_FLASH_DRIVE_SUPPORT && !SDIO_SUPPORT diff --git a/Marlin/src/sd/Sd2Card.h b/Marlin/src/sd/Sd2Card.h index 6900502e03e9..338f86de52e2 100644 --- a/Marlin/src/sd/Sd2Card.h +++ b/Marlin/src/sd/Sd2Card.h @@ -98,6 +98,8 @@ class Sd2Card { Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {} + uint8_t dev_num = -1; + uint32_t cardSize(); bool erase(uint32_t firstBlock, uint32_t lastBlock); bool eraseSingleBlockEnable(); @@ -106,7 +108,13 @@ class Sd2Card { * Set SD error code. * \param[in] code value for error code. */ - inline void error(const uint8_t code) { errorCode_ = code; } + inline void error(const uint8_t code) { + errorCode_ = code; + #ifdef TRACE_SD + SERIAL_ECHO("Error "); + SERIAL_PRINTLN(code, HEX); + #endif + } /** * \return error code for last error. See Sd2Card.h for a list of error codes. @@ -117,12 +125,15 @@ class Sd2Card { inline int errorData() const { return status_; } /** - * Initialize an SD flash memory card with default clock rate and chip - * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). - * + * Initialize the SD flash memory card identified by dev_num + * from its bus with the specified clock rate + * * \return true for success or false for failure. */ - bool init(const uint8_t sckRateID, const pin_t chipSelectPin); + bool init(const uint8_t sckRateID); + + static bool anyInserted(); + static bool isInserted(const uint8_t dev_num); bool readBlock(uint32_t block, uint8_t* dst); @@ -163,8 +174,7 @@ class Sd2Card { bool writeStop(); private: - uint8_t chipSelectPin_, - errorCode_, + uint8_t errorCode_, spiRate_, status_, type_; @@ -178,8 +188,6 @@ class Sd2Card { bool readData(uint8_t* dst, const uint16_t count); bool readRegister(const uint8_t cmd, void* buf); - void chipDeselect(); - void chipSelect(); inline void type(const uint8_t value) { type_ = value; } bool waitNotBusy(const millis_t timeout_ms); bool writeData(const uint8_t token, const uint8_t* src); diff --git a/Marlin/src/sd/SdBaseFile.cpp b/Marlin/src/sd/SdBaseFile.cpp index db2a9e2de9c5..68a97aec8806 100644 --- a/Marlin/src/sd/SdBaseFile.cpp +++ b/Marlin/src/sd/SdBaseFile.cpp @@ -385,7 +385,8 @@ int8_t SdBaseFile::lsPrintNext(uint8_t flags, uint8_t indent) { return DIR_IS_FILE(&dir) ? 1 : 2; } -// Format directory name field from a 8.3 name string +// Format file/directory name to a 8.3 name string +// EG: Filename.Ext becomes FILENAMEEXT bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) { uint8_t n = 7, // Max index until a dot is found i = 11; diff --git a/Marlin/src/sd/SdFatConfig.h b/Marlin/src/sd/SdFatConfig.h index 13ac3a748785..b0b6c739201e 100644 --- a/Marlin/src/sd/SdFatConfig.h +++ b/Marlin/src/sd/SdFatConfig.h @@ -67,10 +67,10 @@ #define FAT12_SUPPORT 0 /** - * SPI init rate for SD initialization commands. Must be 5 (F_CPU/64) - * or 6 (F_CPU/128). + * SPI init rate for SD initialization commands. + * Must be 5 or 6. */ -#define SPI_SD_INIT_RATE 5 +#define SPI_SD_INIT_RATE 6 /** * Set the SS pin high for hardware SPI. If SS is chip select for another SPI diff --git a/Marlin/src/sd/SdInfo.h b/Marlin/src/sd/SdInfo.h index bfa5a01ae2af..b953d173d671 100644 --- a/Marlin/src/sd/SdInfo.h +++ b/Marlin/src/sd/SdInfo.h @@ -61,6 +61,14 @@ uint8_t const CMD0 = 0x00, // GO_IDLE_STATE - init card in spi mode if CS low ACMD23 = 0x17, // SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be pre-erased before writing ACMD41 = 0x29; // SD_SEND_OP_COMD - Sends host capacity support information and activates the card's initialization process +//SD card responses +uint8_t const R1 = 0x01, //basic response + R1b= 0x11, //= R1 + busy (any number of bytes until 0xFF) + R2 = 0x02, //= R1 + status (1 byte) + R3 = 0x03, //= R1 + OCR (4 bytes) + R6 = 0x06, + R7 = 0x07; //= R1 + voltage specifications (4 bytes) + /** status for card in the ready state */ uint8_t const R1_READY_STATE = 0x00; /** status for card in the idle state */ diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index bce84bbd3921..d18d275e47c7 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -378,26 +378,48 @@ void CardReader::mount() { flag.mounted = false; if (root.isOpen()) root.close(); - if (!sd2card.init(SPI_SPEED, SDSS) - #if defined(LCD_SDSS) && (LCD_SDSS != SDSS) - && !sd2card.init(SPI_SPEED, LCD_SDSS) - #endif - ) SERIAL_ECHO_MSG(STR_SD_INIT_FAIL); - else if (!volume.init(&sd2card)) - SERIAL_ERROR_MSG(STR_SD_VOL_INIT_FAIL); - else if (!root.openRoot(&volume)) - SERIAL_ERROR_MSG(STR_SD_OPENROOT_FAIL); + if (!Sd2Card::anyInserted()) + SERIAL_ECHO_MSG("No SD card found..."); else { - flag.mounted = true; - SERIAL_ECHO_MSG(STR_SD_CARD_OK); - } + bool initOK = false; + uint8_t order[] = SD_SEARCH_ORDER; + for (uint8_t i = 0; i < COUNT(order) && !initOK; i++) { + char mess[45]; + sprintf(mess, PSTR("SPI bus %d: Card is "), order[i]); + SERIAL_ECHO(mess); + + for (uint8_t dev = 0; dev < NUM_SPI_DEVICES && !initOK; dev++) + if (BUS_OF_DEV(dev) == order[i] && IS_DEV_SD(dev)) { + if (sd2card.isInserted(dev)) { + SERIAL_ECHOLN("IN -> Initializing..."); + sd2card.dev_num = dev; + initOK = sd2card.init(SPI_SPEED); + } + else + SERIAL_ECHOLN("OUT."); + } + } - if (flag.mounted) - cdroot(); - #if ENABLED(USB_FLASH_DRIVE_SUPPORT) || PIN_EXISTS(SD_DETECT) - else if (marlin_state != MF_INITIALIZING) - ui.set_status_P(GET_TEXT(MSG_SD_INIT_FAIL), -1); - #endif + if (!initOK) // Card not found + SERIAL_ECHO_MSG(MSG_SD_INIT_FAIL); + else if (!volume.init(&sd2card)) + SERIAL_ERROR_MSG(MSG_SD_VOL_INIT_FAIL); + else if (!root.openRoot(&volume)) + SERIAL_ERROR_MSG(MSG_SD_OPENROOT_FAIL); + else { + flag.mounted = true; + SERIAL_ECHO_MSG(MSG_SD_CARD_OK); + #if ENABLED(EEPROM_SETTINGS) && NONE(FLASH_EEPROM_EMULATION, SPI_EEPROM, I2C_EEPROM) + settings.first_load(); + #endif + } + if (flag.mounted) + cdroot(); + #if ENABLED(USB_FLASH_DRIVE_SUPPORT) || PIN_EXISTS(SD_DETECT) + else if (marlin_state != MF_INITIALIZING) + ui.set_status_P(GET_TEXT(MSG_SD_INIT_FAIL), -1); + #endif + } ui.refresh(); } diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h index dabbf719f92b..1237d5f7a37f 100644 --- a/Marlin/src/sd/cardreader.h +++ b/Marlin/src/sd/cardreader.h @@ -281,15 +281,7 @@ class CardReader { #endif }; -#if ENABLED(USB_FLASH_DRIVE_SUPPORT) - #define IS_SD_INSERTED() Sd2Card::isInserted() -#elif PIN_EXISTS(SD_DETECT) - #define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE) -#else - // No card detect line? Assume the card is inserted. - #define IS_SD_INSERTED() true -#endif - +#define IS_SD_INSERTED() Sd2Card::anyInserted() #define IS_SD_PRINTING() card.flag.sdprinting #define IS_SD_PAUSED() card.isPaused() #define IS_SD_FILE_OPEN() card.isFileOpen() diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h index e0e8239aac08..866f8da39c5a 100644 --- a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h +++ b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h @@ -1,4 +1,5 @@ #pragma once +#define USE_SPI_CRC 1 #define HAL_MODULE_ENABLED #define HAL_ADC_MODULE_ENABLED