From c5ee89c95a36ff1335243f9eeca7d4958171ffaf Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 12 Jun 2022 20:16:46 +0200 Subject: [PATCH 01/11] Fix for issue #38. --- grblHAL_Teensy4/src/driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grblHAL_Teensy4/src/driver.c b/grblHAL_Teensy4/src/driver.c index cd300d3..34954bf 100644 --- a/grblHAL_Teensy4/src/driver.c +++ b/grblHAL_Teensy4/src/driver.c @@ -1491,7 +1491,7 @@ static void settings_changed (settings_t *settings) #if SPINDLE_SYNC_ENABLE - if((hal.spindle.get_data = (hal.driver_cap.spindle_at_speed = settings->spindle.ppr > 0) ? spindleGetData : NULL) && + if((hal.spindle.get_data = (hal.spindle.cap.at_speed = settings->spindle.ppr > 0) ? spindleGetData : NULL) && (spindle_encoder.ppr != settings->spindle.ppr || pidf_config_changed(&spindle_tracker.pid, &settings->position.pid))) { hal.spindle.reset_data = spindleDataReset; @@ -2233,7 +2233,7 @@ bool driver_init (void) options[strlen(options) - 1] = '\0'; hal.info = "iMXRT1062"; - hal.driver_version = "220325"; + hal.driver_version = "220517"; #ifdef BOARD_NAME hal.board = BOARD_NAME; #endif From be7db310459c1eda2f73577452cc33ffc0797b40 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 12 Jun 2022 20:17:37 +0200 Subject: [PATCH 02/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- grblHAL_Teensy4/src/webui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index 6d00f74..b55cca1 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit 6d00f743f09db2a07adadf4dc996e3d55de37cdb +Subproject commit b55cca15f953414e99b4dc6c70c4e9fc1eb4fbb4 diff --git a/grblHAL_Teensy4/src/webui b/grblHAL_Teensy4/src/webui index 94b8d50..d001a6c 160000 --- a/grblHAL_Teensy4/src/webui +++ b/grblHAL_Teensy4/src/webui @@ -1 +1 @@ -Subproject commit 94b8d50e2b64e572e337d073f208381ea4d96de4 +Subproject commit d001a6c7c32fd920f41b607daa12b5ba49d0590a From c11d61646a80ff38db0e95f9fa348cba950a31d5 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Thu, 16 Jun 2022 08:59:14 +0200 Subject: [PATCH 03/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- grblHAL_Teensy4/src/spindle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index b55cca1..45b0e10 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit b55cca15f953414e99b4dc6c70c4e9fc1eb4fbb4 +Subproject commit 45b0e105892d08e76d5140871cfb032d445d2f20 diff --git a/grblHAL_Teensy4/src/spindle b/grblHAL_Teensy4/src/spindle index 321150a..2a9f46f 160000 --- a/grblHAL_Teensy4/src/spindle +++ b/grblHAL_Teensy4/src/spindle @@ -1 +1 @@ -Subproject commit 321150aa7a3a10ef7a163a516aee5a77124f4731 +Subproject commit 2a9f46f1f3c963605620e433ec7994507dce3429 From aae11842fa9b60e96827c68c4c40926b637e6f25 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 18 Jun 2022 10:42:51 +0200 Subject: [PATCH 04/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- grblHAL_Teensy4/src/spindle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index 45b0e10..f446881 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit 45b0e105892d08e76d5140871cfb032d445d2f20 +Subproject commit f446881da4a85602928120308cf77985024d5bf4 diff --git a/grblHAL_Teensy4/src/spindle b/grblHAL_Teensy4/src/spindle index 2a9f46f..4400e96 160000 --- a/grblHAL_Teensy4/src/spindle +++ b/grblHAL_Teensy4/src/spindle @@ -1 +1 @@ -Subproject commit 2a9f46f1f3c963605620e433ec7994507dce3429 +Subproject commit 4400e966884cb04aa8fce5689d51687823d5ea74 From 145787c46b637bb320d00d41013f402bf6ed4ed4 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 25 Jun 2022 22:11:30 +0200 Subject: [PATCH 05/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- grblHAL_Teensy4/src/spindle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index f446881..32f905a 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit f446881da4a85602928120308cf77985024d5bf4 +Subproject commit 32f905abb3f95af10771398697a2b349e57e28d5 diff --git a/grblHAL_Teensy4/src/spindle b/grblHAL_Teensy4/src/spindle index 4400e96..d2bc839 160000 --- a/grblHAL_Teensy4/src/spindle +++ b/grblHAL_Teensy4/src/spindle @@ -1 +1 @@ -Subproject commit 4400e966884cb04aa8fce5689d51687823d5ea74 +Subproject commit d2bc839fad61fddd19b5d24654c651c70d5fefb9 From a5da53bf1778f64968e268854f9145f5ab7c72bf Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 4 Jul 2022 14:22:44 +0200 Subject: [PATCH 06/11] Updated for core changes related to the new $9 setting. --- grblHAL_Teensy4/src/driver.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/grblHAL_Teensy4/src/driver.c b/grblHAL_Teensy4/src/driver.c index 34954bf..224ba82 100644 --- a/grblHAL_Teensy4/src/driver.c +++ b/grblHAL_Teensy4/src/driver.c @@ -1164,7 +1164,7 @@ static void spindleSetState (spindle_state_t state, float rpm) static void spindle_set_speed (uint_fast16_t pwm_value) { if (pwm_value == spindle_pwm.off_value) { - if(settings.spindle.flags.pwm_action == SpindleAction_DisableWithZeroSPeed) + if(settings.spindle.flags.enable_rpm_controlled) spindle_off(); pwmEnabled = false; if(spindle_pwm.always_on) { @@ -1215,16 +1215,19 @@ static uint_fast16_t spindleGetPWM (float rpm) // Start or stop spindle. static void spindleSetStateVariable (spindle_state_t state, float rpm) { - if (!state.on || rpm == 0.0f) { - spindle_set_speed(spindle_pwm.off_value); - spindle_off(); - } else { #ifdef SPINDLE_DIRECTION_PIN + if (state.on) spindle_dir(state.ccw); #endif - spindle_set_speed(spindle_compute_pwm_value(&spindle_pwm, rpm, false)); + if(!settings.spindle.flags.enable_rpm_controlled) { + if (state.on) + spindle_on(); + else + spindle_off(); } + spindle_set_speed(state.on ? spindle_compute_pwm_value(&spindle_pwm, rpm, false) : spindle_pwm.off_value); + #if SPINDLE_SYNC_ENABLE if(settings.spindle.at_speed_tolerance > 0.0f) { float tolerance = rpm * settings.spindle.at_speed_tolerance / 100.0f; @@ -1278,7 +1281,7 @@ static void spindlePulseOn (uint_fast16_t pulse_length) bool spindleConfig (void) { - if((hal.spindle.cap.variable = spindle_precompute_pwm_values(&spindle_pwm, F_BUS_ACTUAL / 2))) { + if((hal.spindle.cap.variable = !settings.spindle.flags.pwm_disable && spindle_precompute_pwm_values(&spindle_pwm, F_BUS_ACTUAL / 2))) { #if SPINDLE_PWM_PIN == 12 TMR1_COMP11 = spindle_pwm.period; TMR1_CMPLD11 = spindle_pwm.period; @@ -1295,8 +1298,13 @@ bool spindleConfig (void) TMR2_SCTRL0 &= ~TMR_SCTRL_OPS; #endif hal.spindle.set_state = spindleSetStateVariable; - } else + } else { + if(pwmEnabled) + hal.spindle.set_state((spindle_state_t){0}, 0.0f); hal.spindle.set_state = spindleSetState; + } + + spindle_update_caps(hal.spindle.cap.variable); return true; } @@ -2233,7 +2241,7 @@ bool driver_init (void) options[strlen(options) - 1] = '\0'; hal.info = "iMXRT1062"; - hal.driver_version = "220517"; + hal.driver_version = "220703"; #ifdef BOARD_NAME hal.board = BOARD_NAME; #endif From 7dd77b4d252bca63dd56756026decda8662614bb Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 4 Jul 2022 14:23:30 +0200 Subject: [PATCH 07/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index 32f905a..0db09ab 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit 32f905abb3f95af10771398697a2b349e57e28d5 +Subproject commit 0db09ab6e925842407585158c5937c3729f34059 From e4da0db05ee64d4d20545505aaf18746d2f0e9b9 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 9 Jul 2022 18:42:08 +0200 Subject: [PATCH 08/11] Updated SD card driver patch with workaround for non word-aligned writes that caused file corruption. --- patches/sd_sdhc.c | 1228 +++++++++++++++++++++++++++++++++++++++++++ patches/sd_sdhc.zip | Bin 9726 -> 9796 bytes 2 files changed, 1228 insertions(+) create mode 100644 patches/sd_sdhc.c diff --git a/patches/sd_sdhc.c b/patches/sd_sdhc.c new file mode 100644 index 0000000..59aada5 --- /dev/null +++ b/patches/sd_sdhc.c @@ -0,0 +1,1228 @@ +/* + * WMXZ Teensy uSDFS library + * Copyright (c) 2016 Walter Zimmer. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// following code is modified by Walter Zimmer from +// from version provided by +// Petr Gargulak (NXP Employee) +//https://community.nxp.com/servlet/JiveServlet/download/339474-1-263510/SDHC_K60_Baremetal.ZIP +//see also +//https://community.nxp.com/thread/99202 + +#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) + +#include +#include +#include "core_pins.h" // include calls to kinetis.h or imxrt.h + +// for debugging in C +/* +#include "usb_serial.h" // for Serial +#include +void logg(char c) {usb_serial_putchar(c); usb_serial_flush_output();} +void logVar(char *str, uint32_t var) +{ char txt[80]; sprintf(txt,"%s: 0x%x\n",str,var); usb_serial_write(txt, strlen(txt)+1); usb_serial_flush_output();} +*/ +#include "../ff.h" +#include "../diskio.h" + +#include "sd_sdhc.h" +#include "sdio_priv.h" + + +/****************************************************************************** + Types +******************************************************************************/ +#ifdef OLD +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ + +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR, /* 4: Invalid Parameter */ + RES_NONRSPNS, /* 5: No Response */ // from old diskio.h + RES_READERROR, /* 6: Read Error */ + RES_WRITEERROR /* 7: Write Error */ +} DRESULT; + +#endif + +enum { + SDHC_RESULT_OK = 0, /* 0: Successful */ + SDHC_RESULT_ERROR, /* 1: R/W Error */ + SDHC_RESULT_WRPRT, /* 2: Write Protected */ + SDHC_RESULT_NOT_READY, /* 3: Not Ready */ + SDHC_RESULT_PARERR, /* 4: Invalid Parameter */ + SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h +}; + +#define SDHC_STATUS_NOINIT 0x01 /* Drive not initialized */ +#define SDHC_STATUS_NODISK 0x02 /* No medium in the drive */ +#define SDHC_STATUS_PROTECT 0x04 /* Write protected */ + + +typedef struct { + uint8_t status; + uint8_t highCapacity; + uint8_t version2; + uint8_t tranSpeed; + uint32_t address; + uint32_t numBlocks; + uint32_t lastCardStatus; +} SD_CARD_DESCRIPTOR; + + +/****************************************************************************** + Private variables +******************************************************************************/ + +static SD_CARD_DESCRIPTOR sdCardDesc; + +/****************************************************************************** + Private functions +******************************************************************************/ + +uint8_t sd_CardInit(void); +int sd_CardReadBlocks(void * buff, uint32_t sector, uint32_t count); +int sd_CardWriteBlocks(const void * buff, uint32_t sector, uint32_t count); + +static int sd_CMD0_GoToIdle(void); +static int sd_CMD2_Identify(void); +static int sd_CMD3_GetAddress(void); +static int sd_ACMD6_SetBusWidth(uint32_t address, uint32_t width); +static int sd_CMD7_SelectCard(uint32_t address); +static int sd_CMD8_SetInterface(uint32_t cond); +static int sd_CMD9_GetParameters(uint32_t address); +static int sd_CMD16_SetBlockSize(uint32_t block_size); +//static int sd_CMD17_ReadBlock(uint32_t sector); +//static int sd_CMD24_WriteBlock(uint32_t sector); +static int sd_ACMD41_SendOperationCond(uint32_t cond); + +static int sd_CMD12_StopTransferWaitForBusy(void); +static int sd_CMD13_WaitForReady(uint32_t address); + +/****************************************************************************** + + Global functions + +******************************************************************************/ + +DSTATUS SDHC_disk_status() +{ return (DSTATUS) sdCardDesc.status; +} + +DSTATUS SDHC_disk_initialize() +{ return (DSTATUS) sd_CardInit(); +} + +DRESULT SDHC_disk_read(BYTE *buff, DWORD sector, UINT count) +{ return (DRESULT) sd_CardReadBlocks((void *) buff, (uint32_t) sector, (uint32_t) count); +} + +DRESULT SDHC_disk_write(const BYTE *buff, DWORD sector, UINT count) +{ return (DRESULT) sd_CardWriteBlocks((void *) buff, (uint32_t) sector, (uint32_t) count); +} + +DRESULT SDHC_disk_ioctl(BYTE cmd, BYTE *buff) +{ return RES_OK; +} + + + + +#define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN) + +/****************************************************************************** + local functions +******************************************************************************/ + +#if defined(__MK64FX512__) || defined(__MK66FX1M0__) + // initialize the SDHC Controller signals + static void sd_InitGPIO(void) + { + PORTE_PCR0 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D1 */ + PORTE_PCR1 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D0 */ + PORTE_PCR2 = PORT_PCR_MUX(4) | PORT_PCR_DSE; /* SDHC.CLK */ + PORTE_PCR3 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.CMD */ + PORTE_PCR4 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D3 */ + PORTE_PCR5 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D2 */ + } + + // release the SDHC Controller signals + static void sd_ReleaseGPIO(void) + { + PORTE_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D1 */ + PORTE_PCR1 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D0 */ + PORTE_PCR2 = 0; /* SDHC.CLK */ + PORTE_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.CMD */ + PORTE_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D3 */ + PORTE_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D2 */ + } + + static void initClock() + { + #ifdef HAS_KINETIS_MPU + // Allow SDHC Bus Master access. + MPU_RGDAAC0 |= 0x0C000000; + #endif + // Enable SDHC clock. + SIM_SCGC3 |= SIM_SCGC3_SDHC; + } + + static uint32_t sdClock() + { return F_CPU; + } + +#else + + static void sd_InitGPIO(void) + { + { //T4 // Inverted pins(T4) + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 0; //DAT2 + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 0; //DAT3 + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 0; //CMD + //3.3V + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 0; //CLK + //GND + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 0; //DAT0 + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 0; //DAT1 + + const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE | + IOMUXC_SW_PAD_CTL_PAD_DSE(1) | + IOMUXC_SW_PAD_CTL_PAD_SPEED(2); + + const uint32_t DATA_MASK = CLOCK_MASK | + (IOMUXC_SW_PAD_CTL_PAD_PUE | IOMUXC_SW_PAD_CTL_PAD_PUS(1)); + + IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK; + IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_05 = DATA_MASK; + IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 = DATA_MASK; + IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_01 = CLOCK_MASK; + IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_02 = DATA_MASK; + IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_03 = DATA_MASK; + } + } + + static void sd_ReleaseGPIO(void) + { + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 5; //GPIO3_IO16 + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 5; //GPIO3_IO17 + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 5; //GPIO3_IO12 + //3.3V + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 5; //GPIO3_IO13 + //GND + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 5; //GPIO3_IO14 + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 5; //GPIO3_IO15 + } + + static void initClock() + { + /* set PDF_528 PLL2PFD0 */ + CCM_ANALOG_PFD_528 |= (1 << 7); + CCM_ANALOG_PFD_528 &= ~(0x3F << 0); + CCM_ANALOG_PFD_528 |= ((24) & 0x3F << 0); // 12 - 35 + CCM_ANALOG_PFD_528 &= ~(1 << 7); + + /* Enable USDHC clock. */ + CCM_CCGR6 |= CCM_CCGR6_USDHC1(CCM_CCGR_ON); + CCM_CSCDR1 &= ~(CCM_CSCDR1_USDHC1_CLK_PODF_MASK); + // + // CCM_CSCMR1 &= ~(CCM_CSCMR1_USDHC1_CLK_SEL); // PLL2PFD2 + CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0 + CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); // &0x7 + + // for testing + CCM_CCOSR = CCM_CCOSR_CLKO1_EN | CCM_CCOSR_CLKO1_DIV(7) | CCM_CCOSR_CLKO1_SEL(1); //(1: SYS_PLL/2) + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 6; //CCM_CLKO1 (0 is USDHC1_DAT2) + // for testing + CCM_CCOSR |= (CCM_CCOSR_CLKO2_EN | CCM_CCOSR_CLKO2_DIV(7) | CCM_CCOSR_CLKO2_SEL(3)); //(3: usdhc1_clk_root)) + IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 6; //CCM_CLKO2 (0 is USDHC1_DAT3) + } + + static uint32_t sdClock() + { + uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1; + uint32_t PLL2PFD0 = (528000000U * 3) / ((CCM_ANALOG_PFD_528 & 0x3F) / 6) / divider; + return PLL2PFD0; + } + +#endif + +static void setSdclk(uint32_t kHzMax) { + const uint32_t DVS_LIMIT = 0X10; + const uint32_t SDCLKFS_LIMIT = 0X100; + uint32_t dvs = 1; + uint32_t sdclkfs = 1; + uint32_t maxSdclk = 1000 * kHzMax; + + // uint32_t f_pll = F_CPU; + uint32_t f_pll = sdClock(); + + while ((f_pll / (sdclkfs * DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) { + sdclkfs <<= 1; + } + while ((f_pll / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) { + dvs++; + } + // unused // uint32_t m_sdClkKhz = f_pll / (1000 * sdclkfs * dvs); + + sdclkfs >>= 1; + dvs--; + + #if defined(__MK64FX512__) || defined(__MK66FX1M0__) + // Disable SDHC clock. + SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN; + #endif + + // Change dividers. + uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK + | SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK); + + SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs) + | SDHC_SYSCTL_SDCLKFS(sdclkfs); + + // Wait until the SDHC clock is stable. + while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) { } + + #if defined(__MK64FX512__) || defined(__MK66FX1M0__) + // Enable the SDHC clock. + SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN; + #endif +} + + +/****************************************************************************** + + SDHC functions + +******************************************************************************/ + +static volatile uint32_t dmaDone=0; +// + +void sd_isr(void) +{ SDHC_IRQSIGEN &= ~SDHC_IRQSIGEN_DMA_MASK; + // + while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC));// SDHC_IRQSTAT &= ~SDHC_IRQSTAT_TC; + + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) + SDHC_MIX_CTRL &= ~(SDHC_MIX_CTRL_AC23EN | SDHC_MIX_CTRL_DMAEN) ; + #endif + + if(SDHC_SYSCTL & SDHC_SYSCTL_HCKEN) SDHC_SYSCTL &= ~SDHC_SYSCTL_HCKEN; + SDHC_PROCTL &= ~SDHC_PROCTL_D3CD; SDHC_PROCTL |= SDHC_PROCTL_D3CD; + + dmaDone=1; +} + +// initialize the SDHC Controller +// returns status of initialization(OK, nonInit, noCard, CardProtected) +static uint8_t sd_Init(void) +{ + initClock(); + + // De-init GPIO - to prevent unwanted clocks on bus + sd_ReleaseGPIO(); + #if defined (__IMXRT1052__) || defined (__IMXRT1062__) + SDHC_SYSCTL |= 0xF; + SDHC_MIX_CTRL |= 0x80000000; + #endif + + /* Reset SDHC */ + SDHC_SYSCTL |= SDHC_SYSCTL_RSTA | SDHC_SYSCTL_SDCLKFS(0x80); + while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) ; // wait + + /* Set the SDHC initial baud rate divider and start */ + setSdclk(400); + + /* Poll inhibit bits */ + while (SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB)) ; + + /* Init GPIO again */ + sd_InitGPIO(); + + /* Initial values */ // to do - Check values +// SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512); + + SDHC_PROCTL &= ~SDHC_PROCTL_DMAS(3); // clear ADMA + + SDHC_PROCTL |= SDHC_PROCTL_D3CD; + // SDHC_PROCTL = SDHC_PROCTL_EMODE(SDHC_PROCTL_EMODE_INVARIANT) | SDHC_PROCTL_D3CD; + // SDHC_WML |= SDHC_WML_RDWML(SDHC_FIFO_BUFFER_SIZE) | SDHC_WML_WRWML(SDHC_FIFO_BUFFER_SIZE); + + #if defined(__IMXRT1052__) || defined (__IMXRT1062__) + SDHC_VENDOR = 0x2000F801; // (1<<29 | 0x1F<<11 | 1); + SDHC_VENDOR2 &= ~(1<<12); //switch off ACMD23 sharing SDMA + #endif + + // clear interrupt status + SDHC_IRQSTAT = SDHC_IRQSTAT; + + /* Enable requests */ + SDHC_IRQSTATEN = SDHC_IRQSTAT_CRM | SDHC_IRQSTATEN_CIESEN | + SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; + + attachInterruptVector(IRQ_SDHC, sd_isr); + NVIC_SET_PRIORITY(IRQ_SDHC, 6 * 16); + NVIC_ENABLE_IRQ(IRQ_SDHC); + + // initial clocks... SD spec says only 74 clocks are needed, but if Teensy rebooted + // while the card was in middle of an operation, thousands of clock cycles can be + // needed to get the card to complete a prior command and return to a usable state. + for (int ii = 0; ii < 500; ii++) { + SDHC_SYSCTL |= SDHC_SYSCTL_INITA; + while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) ; + } + + if(!(SDHC_PRSSTAT & SDHC_PRSSTAT_CINS)) return SDHC_STATUS_NODISK; + return 0; +} + +uint8_t SDHC_GetCardType(void) +{ + if (sdCardDesc.status) return 0; + if (sdCardDesc.version2 == 0) return 1; // SD_CARD_TYPE_SD1 + if (sdCardDesc.highCapacity == 0) return 2; // SD_CARD_TYPE_SD2 + return 3; // SD_CARD_TYPE_SDHC +} + +//----------------------------------------------------------------------------- +// initialize the SDHC Controller and SD Card +// returns status of initialization(OK, nonInit, noCard, CardProtected) +uint8_t sd_CardInit(void) +{ + uint8_t resS; + int resR; + + resS = sd_Init(); + + sdCardDesc.status = resS; + sdCardDesc.address = 0; + sdCardDesc.highCapacity = 0; + sdCardDesc.version2 = 0; + sdCardDesc.numBlocks = 0; + + if (resS) return resS; + + SDHC_IRQSIGEN = 0; + #if defined (__IMXRT1052__) || defined(__IMXRT1062__) + uint32_t mixCtrl = 0x80000000; //SDHC_MIX_CTRL; + // mixCtrl |= SDHC_MIX_CTRL_BCEN; // does not hurt + // mixCtrl |= SDHC_MIX_CTRL_DTDSEL; // write/read (will be set later + // mixCtrl |= SDHC_MIX_CTRL_MSBSEL; //for multi block transfer + // mixCtrl |= SDHC_MIX_CTRL_AC12EN; //for multi block transfer + // mixCtrl |= SDHC_MIX_CTRL_AC23EN; + SDHC_MIX_CTRL = mixCtrl; + #endif + + resR = sd_CMD0_GoToIdle(); + if (resR) { return sdCardDesc.status = SDHC_STATUS_NOINIT;} + resR = sd_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern + if (resR == SDHC_RESULT_OK) + { if (!((SDHC_CMDRSP0 & 0x000001AA)== 0x000001AA)) return sdCardDesc.status = SDHC_STATUS_NOINIT; + sdCardDesc.highCapacity = 1; + } + else if (resR == SDHC_RESULT_NO_RESPONSE) + { // version 1 cards do not respond to CMD8 + } + else return sdCardDesc.status = SDHC_STATUS_NOINIT; + + if (sd_ACMD41_SendOperationCond(0)) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + if (SDHC_CMDRSP0 & 0x300000) { + uint32_t condition = 0x00300000; + if (sdCardDesc.highCapacity) condition |= 0x40000000; + // + uint32_t ii = 0; + do { + ii++; + if (sd_ACMD41_SendOperationCond(condition)) { + resS = SDHC_STATUS_NOINIT; + break; + } + } while ((!(SDHC_CMDRSP0 & 0x80000000)) && (ii < SDHC_INITIALIZATION_MAX_CNT)); + + if (resS) return resS; + + if ((ii >= SDHC_INITIALIZATION_MAX_CNT) || (!(SDHC_CMDRSP0 & 0x40000000))) + sdCardDesc.highCapacity = 0; + } + + // Card identify + SDHC_CMDRSP0=SDHC_CMDRSP1=SDHC_CMDRSP2=SDHC_CMDRSP3=0; + if (sd_CMD2_Identify()) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + // Get card address + if (sd_CMD3_GetAddress()) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + sdCardDesc.address = SDHC_CMDRSP0 & 0xFFFF0000; + + + // Get card parameters + if (sd_CMD9_GetParameters(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + if (!(SDHC_CMDRSP3 & 0x00C00000)) { + uint32_t read_bl_len, c_size, c_size_mult; + + read_bl_len = (SDHC_CMDRSP2 >> 8) & 0x0F; + c_size = SDHC_CMDRSP2 & 0x03; + c_size = (c_size << 10) | (SDHC_CMDRSP1 >> 22); + c_size_mult = (SDHC_CMDRSP1 >> 7) & 0x07; + sdCardDesc.numBlocks = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << (read_bl_len - 9)); + } else { + uint32_t c_size; + sdCardDesc.version2 = 1; + c_size = (SDHC_CMDRSP1 >> 8) & 0x003FFFFF; + sdCardDesc.numBlocks = (c_size + 1) << 10; + } + + // Select card + if (sd_CMD7_SelectCard(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + // Set 512 Block size in SD card + if (sd_CMD16_SetBlockSize(SDHC_BLOCK_SIZE)) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + // Set 4 bit data bus width + if (sd_ACMD6_SetBusWidth(sdCardDesc.address, 2)) return sdCardDesc.status = SDHC_STATUS_NOINIT; + + // Set Data bus width also in SDHC controller + SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK; + SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); +// SDHC_PROCTL |= SDHC_PROTCT_BURST_LENEN(7); + + // De-Init GPIO + sd_ReleaseGPIO(); + + // Set the SDHC default baud rate + setSdclk(60000); + // SDHC_SetClock(SDHC_SYSCTL_25MHZ); + // TODO: use CMD6 and CMD9 to detect if card supports 50 MHz + // then use CMD4 to configure card to high speed mode, + // and SDHC_SetClock() for 50 MHz config + + // Init GPIO + sd_InitGPIO(); + + return sdCardDesc.status; +} + + +//----------------------------------------------------------------------------- +// FUNCTION: sd_CardReadBlock (disk_read) +// SCOPE: SDHC public related function +// DESCRIPTION: Function read block to disk +// +// PARAMETERS: buff - pointer on buffer where read data should be stored +// sector - index of sector +// count - number of secorts +// +// RETURNS: result of operation +//----------------------------------------------------------------------------- +#define SDHC_CMD17_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD17) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ + | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN | SDHC_XFERTYP_DTDSEL) +#define SDHC_CMD18_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD18) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ + | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN | SDHC_XFERTYP_DTDSEL \ + | SDHC_XFERTYP_AC12EN| SDHC_XFERTYP_BCEN | SDHC_XFERTYP_MSBSEL ) +// +int sd_CardReadBlocks(void * buff, uint32_t sector, uint32_t count) +{ + int result=0; + // unused // uint32_t* pData = (uint32_t*)buff; + + + // Convert LBA to BYTE address if needed + if (!sdCardDesc.highCapacity) sector *= 512; + + // Check if this is ready + if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; + + while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) ; + + // clear status + SDHC_IRQSTAT = SDHC_IRQSTAT; + + // use dma: disabling polling + uint32_t irqstat = SDHC_IRQSTATEN; + irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; + irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; + // enable status + irqstat |= /*SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN |*/ SDHC_IRQSTATEN_DMAESEN ; + irqstat |= SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ;//| SDHC_IRQSTATEN_CCSEN ; + SDHC_IRQSTATEN = irqstat; + + uint32_t sigen = SDHC_IRQSIGEN; + sigen |= SDHC_IRQSIGEN_DMA_MASK ; + SDHC_IRQSIGEN = sigen; + + SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) + + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL ; // read + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; // DMA + SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_BCEN; // Block Count + SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_MSBSEL; //for multi block transfer + SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_AC12EN; //for multi block transfer + if(count>1) + { + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_BCEN; // Block Count + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_MSBSEL; //for multi block transfer + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_AC12EN; //for multi block transfer + } + #endif + SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); + + // enable DMA + dmaDone=0; + SDHC_DSADDR = (uint32_t)buff; + +#if defined(__IMXRT1062__) + if((uint32_t)buff >= 0x20200000U) + arm_dcache_flush_delete((void *)buff, 512 * count); +#endif + + // send command + SDHC_CMDARG = sector; + SDHC_XFERTYP = count==1 ? SDHC_CMD17_XFERTYP: SDHC_CMD18_XFERTYP; + + // wait for DMA + while(!dmaDone); + SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); + +#if defined(__IMXRT1062__) + if((uint32_t)buff >= 0x20200000U) + arm_dcache_flush_delete((void *)buff, 512 * count); +#endif + + // Auto CMD12 is enabled for DMA so call it if DMA error + if((SDHC_DSADDR < (uint32_t)(buff+(count*512))) && (count>1)) + result=sd_CMD12_StopTransferWaitForBusy(); + + return result; +} + +//----------------------------------------------------------------------------- +// FUNCTION: sd_CardWriteBlock (disk_write) +// SCOPE: SDHC public related function +// DESCRIPTION: Function write block to disk +// +// PARAMETERS: buff - pointer on buffer where is stored data +// sector - index of sector +// +// RETURNS: result of operation +//----------------------------------------------------------------------------- +#define SDHC_CMD24_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD24) |SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ + | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN) + //| SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN | SDHC_XFERTYP_MSBSEL + +#define SDHC_CMD25_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD25) |SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ + | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN \ + | SDHC_XFERTYP_AC12EN| SDHC_XFERTYP_BCEN | SDHC_XFERTYP_MSBSEL ) +// +int sd_CardWriteBlocks(const void * buff, uint32_t sector, uint32_t count) +{ + int result=0; + void *buff2 = NULL; + // unused // const uint32_t *pData = (const uint32_t *)buff; + + // Convert LBA to uint8_t address if needed + if (!sdCardDesc.highCapacity) sector *= 512; + + // Check if this is ready + if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; + + while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) ; + + // clear status + SDHC_IRQSTAT = SDHC_IRQSTAT; + + uint32_t irqstat = SDHC_IRQSTATEN; + // use dma: disabling polling + irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; + irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; + // enable status + irqstat |= SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN | SDHC_IRQSTATEN_DMAESEN ; + irqstat |= SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ;//| SDHC_IRQSTATEN_CCSEN ; + SDHC_IRQSTATEN = irqstat; + + uint32_t sigen = SDHC_IRQSIGEN; + sigen |= SDHC_IRQSIGEN_DMA_MASK ; + SDHC_IRQSIGEN = sigen; + + SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) + SDHC_MIX_CTRL &= ~ SDHC_MIX_CTRL_DTDSEL; // write + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; //DMA + SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_BCEN; // Block Count + SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_MSBSEL; //for multi block transfer + SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_AC12EN; //for multi block transfer + if(count>1) + { + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_BCEN; // Block Count + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_MSBSEL; //for multi block transfer + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_AC12EN; //for multi block transfer + } + #endif + SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); + + if((uint32_t)buff % 4) { + if((buff2 = malloc(512 * count))) + buff = memcpy(buff2, buff, 512 * count); + } + +#if defined(__IMXRT1062__) + if((uint32_t)buff >= 0x20200000U) + arm_dcache_flush_delete((void *)buff, 512 * count); +#endif + + // enable DMA + dmaDone=0; + SDHC_DSADDR = (uint32_t)buff; + // + // send write command + SDHC_CMDARG = sector; + SDHC_XFERTYP = count==1 ? SDHC_CMD24_XFERTYP: SDHC_CMD25_XFERTYP; + // + // wait for DMA to finish + while(!dmaDone); + + SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); + while(SDHC_PRSSTAT & SDHC_PRSSTAT_DLA); + + //check for SD status (if data are written?) + result = sd_CMD13_WaitForReady(sdCardDesc.address); + + if(buff2) + free(buff2); + + // Auto CMD12 is enabled for DMA so call it when transfer error + if((result != SDHC_RESULT_OK) && (count>1)) + result=sd_CMD12_StopTransferWaitForBusy(); + + return result; +} + +/****************************************************************************** + + Private functions + +******************************************************************************/ +// waits for status bits sets +static uint32_t sd_WaitStatus(uint32_t mask) +{ + uint32_t result; + uint32_t timeout = 1 << 24; + do + { result = SDHC_IRQSTAT & mask; + timeout--; + } while (!result && (timeout)); + if (timeout) return result; + return 0; +} + +/***************************** LOW Level SDHC interface ********************************/ +// sends the command to SDcard +static int sd_CMD(uint32_t xfertyp, uint32_t arg) +{ + // Card removal check preparation + SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM; + + // Wait for cmd line idle // to do timeout PRSSTAT[CDIHB] and the PRSSTAT[CIHB] + while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)); + + // send command + SDHC_CMDARG = arg; + SDHC_XFERTYP = xfertyp; + + /* Wait for response */ + const uint32_t mask = SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE | SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CC; + if (sd_WaitStatus(mask) != SDHC_IRQSTAT_CC) + { SDHC_IRQSTAT |= mask; + return SDHC_RESULT_ERROR; + } + return SDHC_RESULT_OK; + + /* Check card removal */ + if (SDHC_IRQSTAT & SDHC_IRQSTAT_CRM) + { SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC; + return SDHC_RESULT_NOT_READY; + } + + /* Get response, if available */ + if (SDHC_IRQSTAT & SDHC_IRQSTAT_CTOE) + { SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC; + return SDHC_RESULT_NO_RESPONSE; + } + SDHC_IRQSTAT |= SDHC_IRQSTAT_CC; + + return SDHC_RESULT_OK; +} + +// send CMD 55 Application specific command +#define SDHC_CMD55_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD55) | SDHC_XFERTYP_CICEN | \ + SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) + +static int sd_ACMD(uint32_t xfertyp, uint32_t arg1, uint32_t arg2) +{ + int result =sd_CMD(SDHC_CMD55_XFERTYP,arg1); + if(!(result == SDHC_RESULT_OK)) return result; + return sd_CMD(xfertyp,arg2); +} + +/* + * Convenience interfaces + */ +// ---------- sends CMD0 to put SDCARD to idle +#define SDHC_CMD0_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD0) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_NO)) +// +static int sd_CMD0_GoToIdle(void){ return sd_CMD(SDHC_CMD0_XFERTYP,0); } + +// ---------- sends CMD2 to identify card +#define SDHC_CMD2_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD2) | SDHC_XFERTYP_CCCEN \ + | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136)) +// +static int sd_CMD2_Identify(void){ return sd_CMD(SDHC_CMD2_XFERTYP,0); } + +// ---------- sends CMD 3 to get address +#define SDHC_CMD3_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD3) | SDHC_XFERTYP_CICEN | \ + SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) +// +static int sd_CMD3_GetAddress(void){ return sd_CMD(SDHC_CMD3_XFERTYP,0); } + + +// ---------- sends ACMD6 to set bus width +#define SDHC_ACMD6_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_ACMD6) | SDHC_XFERTYP_CICEN | \ + SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) +// +static int sd_ACMD6_SetBusWidth(uint32_t address, uint32_t width) +{ return sd_ACMD(SDHC_ACMD6_XFERTYP,address, width); } + + +// ---------- sends CMD 7 to select card +#define SDHC_CMD7_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD7) | SDHC_XFERTYP_CICEN | \ + SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48BUSY)) +// +static int sd_CMD7_SelectCard(uint32_t address){ return sd_CMD(SDHC_CMD7_XFERTYP, address);} + +// ---------- CMD8 to send interface condition +#define SDHC_CMD8_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD8) | SDHC_XFERTYP_CICEN | \ + SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) +// +static int sd_CMD8_SetInterface(uint32_t cond){ return sd_CMD(SDHC_CMD8_XFERTYP, cond); } + +// ---------- sends CMD 9 to get interface condition +#define SDHC_CMD9_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD9) | SDHC_XFERTYP_CCCEN | \ + SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136)) +// +static int sd_CMD9_GetParameters(uint32_t address) +{ + int result = sd_CMD(SDHC_CMD9_XFERTYP, address); + if (result == SDHC_RESULT_OK) { sdCardDesc.tranSpeed = SDHC_CMDRSP2 >> 24;} + return result; +} + +// ---------- sends CMD12 to stop transfer +#define SDHC_CMD12_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD12) | SDHC_XFERTYP_CMDTYP(SDHC_XFERTYP_CMDTYP_ABORT) | \ + SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48BUSY)) +// +static int sd_CMD12_StopTransfer(void){ return sd_CMD(SDHC_CMD12_XFERTYP, 0);} + +// ---------- sends CMD12 to stop transfer and first waits to ready SDCard +static int sd_CMD12_StopTransferWaitForBusy(void) +{ + uint32_t timeOut = 1000; + int result; + do + { result = sd_CMD12_StopTransfer(); + timeOut--; + } while (timeOut && (SDHC_PRSSTAT & SDHC_PRSSTAT_DLA) && result == SDHC_RESULT_OK); + + if (result != SDHC_RESULT_OK) return result; + if (!timeOut) return SDHC_RESULT_NO_RESPONSE; + + return SDHC_RESULT_OK; +} + +// ---------- sends CMD13 to check uSD status +#define SDHC_CMD13_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD13) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) +// +static int sd_CMD13_Check_Status(uint32_t address){ return sd_CMD(SDHC_CMD13_XFERTYP, address);} + +#define CARD_STATUS_READY_FOR_DATA (1UL << 8) +// ---------- sends CMD13 to check uSD status and wait for ready +static int sd_CMD13_WaitForReady(uint32_t address) +{ int result; + do + { while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) ; + SDHC_IRQSTATEN |= SDHC_IRQSTATEN_CCSEN; + SDHC_IRQSTAT=SDHC_IRQSTAT; + // CMD13 to check uSD status + result = sd_CMD13_Check_Status(sdCardDesc.address); + if (result != SDHC_RESULT_OK) return result; + } while(!((SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA)==CARD_STATUS_READY_FOR_DATA)); // while data? + return SDHC_RESULT_OK; +} + +// ---------- sends CMD16 to set block size +#define SDHC_CMD16_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD16) | SDHC_XFERTYP_CICEN | \ + SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) +// +static int sd_CMD16_SetBlockSize(uint32_t block_size){ return sd_CMD(SDHC_CMD16_XFERTYP, block_size);} + +// ---------- ACMD 41 to send operation condition +#define SDHC_ACMD41_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_ACMD41) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) +// +static int sd_ACMD41_SendOperationCond(uint32_t cond){ return sd_ACMD(SDHC_ACMD41_XFERTYP,0, cond);} + + +#endif // __MK64FX512__ or __MK66FX1M0__ or __IMXRT1052__ or __IMXRT1062__ + + + + + + + + + + + + + + +#ifdef XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +#if defined(__MK66FX1M0__) || defined (__MK64FX512__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) +#include "sd_defs.h" +#include "sd_sdhc.h" + +#include "sdio.h" +#include "sdio_priv.h" + +#define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN) +SD_CARD_DESCRIPTOR sdCardDesc; + +int SDHC_disk_status() +{ + return sdCardDesc.status; +} + +int SDHC_disk_initialize() +{ + DSTATUS resS; + + uint32_t kbaudrate; + + resS = sdhc_Init(); + + sdCardDesc.status = resS; + sdCardDesc.address = 0; + sdCardDesc.highCapacity = 0; + sdCardDesc.version2 = 0; + sdCardDesc.numBlocks = 0; + + if(resS) return resS; + if(!sdhc_CMD(SDHC_CMD0_XFERTYP, 0)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD0); + + if(sdhc_CMD(SDHC_CMD8_XFERTYP, 0X1AA)) // 3.3V and AA check pattern + { + if (SDHC_CMDRSP0 != 0X1AA) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD8); + sdCardDesc.version2 = 1; + } + + uint32_t arg = sdCardDesc.version2 ? 0X40300000 : 0x00300000; + int ii = SDHC_INITIALIZATION_MAX_CNT; + do { + if(!(sdhc_CMD(SDHC_CMD55_XFERTYP,0) && sdhc_CMD(SDHC_ACMD41_XFERTYP,arg)) || !ii ) + SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_ACMD41); + } while ((SDHC_CMDRSP0 & 0x80000000) == 0 && ii--); + + m_sdhc_ocr = SDHC_CMDRSP0; + if (SDHC_CMDRSP0 & 0x40000000) + { // is high capacity + sdCardDesc.highCapacity = 1; + } + + // Card identify + if(!sdhc_CMD(SDHC_CMD2_XFERTYP,0)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD2); + + // Get card address + if(!sdhc_CMD(SDHC_CMD3_XFERTYP,0)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD3); + + sdCardDesc.address = SDHC_CMDRSP0 & 0xFFFF0000; + + // Get card parameters + if(!sdhc_CMD(SDHC_CMD9_XFERTYP,sdCardDesc.address)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD9); + if (0 == (SDHC_CMDRSP3 & 0x00C00000)) + { + LWord read_bl_len, c_size, c_size_mult; + + read_bl_len = (SDHC_CMDRSP2 >> 8) & 0x0F; + c_size = SDHC_CMDRSP2 & 0x03; + c_size = (c_size << 10) | (SDHC_CMDRSP1 >> 22); + c_size_mult = (SDHC_CMDRSP1 >> 7) & 0x07; + sdCardDesc.numBlocks = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << (read_bl_len - 9)); + } + else + { + LWord c_size; + + sdCardDesc.version2 = 1; + c_size = (SDHC_CMDRSP1 >> 8) & 0x003FFFFF; + sdCardDesc.numBlocks = (c_size + 1) << 10; + } + + if(!sdhc_CMD(SDHC_CMD10_XFERTYP,sdCardDesc.address)) {SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD10);} + else + { uint8_t d[16]; + d[0] = SDHC_CMDRSP3 >> 16; + d[1] = SDHC_CMDRSP3 >> 8; + d[2] = SDHC_CMDRSP3; + d[3] = SDHC_CMDRSP2 >> 24; + d[4] = SDHC_CMDRSP2 >> 16; + d[5] = SDHC_CMDRSP2 >> 8; + d[6] = SDHC_CMDRSP2; + d[7] = SDHC_CMDRSP1 >> 24; + d[8] = SDHC_CMDRSP1 >> 16; + d[9] = SDHC_CMDRSP1 >> 8; + d[10] = SDHC_CMDRSP1; + d[11] = SDHC_CMDRSP0 >> 24; + d[12] = SDHC_CMDRSP0 >> 16; + d[13] = SDHC_CMDRSP0 >> 8; + d[14] = SDHC_CMDRSP0; + d[15] = 0; + } // function not used yet + +logg('h'); + // Select card + if(!sdhc_CMD(SDHC_CMD7_XFERTYP,sdCardDesc.address)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD7); + +logg('j'); + // Set Block Size to 512 + // Block Size in SDHC Controller is already set to 512 by SDHC_Init(); + // Set 512 Block size in SD card + if(!sdhc_CMD(SDHC_CMD16_XFERTYP,SDHC_BLOCK_SIZE)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD16); + +logg('k'); + if(SDHC_DO4BITS) + { + // Set 4 bit data bus width + if(!(sdhc_CMD(SDHC_CMD55_XFERTYP,sdCardDesc.address) && sdhc_CMD(SDHC_ACMD6_XFERTYP,2))) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_ACMD6); + + // Set Data bus width also in SDHC controller + SDHC_PROCTL &= (~ SDHC_PROCTL_DTW_MASK); + SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); + } +logg('l'); + +#if defined(__MK66FX1M0__) || defined (__MK64FX512__) + #if SDHC_USE_ISR == 1 + // adapted from Bill Greiman + // but he has last condition wrong (following section 60.7.4.2 in K66P144M180SF5RMV2.pdf) + if(sdhc_CMD6_Switch(0X00FFFFF1,m_sdhc_CMD6_Status) && (m_sdhc_CMD6_Status[13] & 2) && + sdhc_CMD6_Switch(0X80FFFFF1,m_sdhc_CMD6_Status) && !((m_sdhc_CMD6_Status[16] & 0xF) == 0xf)) + kbaudrate = 60000; + else + kbaudrate = 25000; + #else + kbaudrate = 50000; + #endif +#else + kbaudrate = 50000; +#endif +/* + // De-Init GPIO + sdhc_InitGPIO(3); + + // Set the SDHC default baud rate + sdhc_SetBaudrate(kbaudrate); + + // Init GPIO + sdhc_InitGPIO(0xFFFF); +*/ +logg('m'); + return sdCardDesc.status; +} + +int SDHC_disk_read(BYTE *buff, DWORD sector, UINT count) +{ + DRESULT result = RES_OK; + LWord* pData = (LWord*)buff; +logg('A'); + // Check if this is ready + if(sdCardDesc.status != 0) return RES_NOTRDY; +logg('B'); + + // Check the valid Count of block + if(!count) return RES_PARERR; + + // Convert LBA to UCHAR address if needed + if(!sdCardDesc.highCapacity) sector *= 512; + +// delayMicroseconds(100); // this is workaround to avoid sdhc blocking on BREN +// m_sdhc_waitCmd13 = 1; +// uint32_t cnt = 1<<16; while ((--cnt) && sdhc_isBusy()) /* yield() */; if(!cnt) return RES_READERROR; +// m_sdhc_waitCmd13 = 0; +logg('C'); + + while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) /* yield() */; +logg('D'); + + SDHC_IRQSTAT = SDHC_IRQSTAT; // clear interrupt status register + + // + #if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA + SDHC_DSADDR = (LWord)pData; + SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; + #endif + + // use dma: disabling polling + uint32_t irqstat = SDHC_IRQSTATEN; + irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; + irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; + // enable status + irqstat |= SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ; + SDHC_IRQSTATEN = irqstat; + + uint32_t sigen = SDHC_IRQSIGEN; + sigen |= SDHC_IRQSIGEN_DMA_MASK ; + SDHC_IRQSIGEN = sigen; + + SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(SDHC_BLOCK_SIZE); + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL ; // read + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; // DMA + #endif + sdhc_enableDma(); +logg('E'); + + SDHC_CMDARG = sector; + SDHC_XFERTYP = count==1 ? SDHC_CMD17_XFERTYP: SDHC_CMD18_XFERTYP; + + #if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_SWPOLL + if(sdhc_waitCommandReady()) + result = sdhc_ReadBlock(pData,count,SDHC_BLOCK_SIZE); + else + result=RES_READERROR; + #elif SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA + result=RES_OK; + #endif +logg('F'); + // Auto CMD12 is enabled + if((result != RES_OK) && (count>1)) + result=sdhc_CMD12_StopTransferWaitForBusy(); + // wait for end of DMA +logg('G'); + sdhc_DMAWait(); + SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); +logg('H'); + + return result; +} + +int SDHC_disk_write(const BYTE *buff, DWORD sector, UINT count) +{ + DRESULT result = RES_OK; + LWord* pData = (LWord*)buff; + + // Check if this is ready + if(sdCardDesc.status != 0) return RES_NOTRDY; + + // Check the valid Count of block + if(!count) return RES_PARERR; + + // Convert LBA to UCHAR address if needed + if(!sdCardDesc.highCapacity) sector *= 512; + +// delayMicroseconds(100); // this is workaround to avoid sdhc blocking on BWEN + m_sdhc_waitCmd13 = 1; + uint32_t cnt = 1<<16; while ((--cnt) && sdhc_isBusy()) /* yield() */; if(!cnt) return RES_WRITEERROR; + m_sdhc_waitCmd13 = 0; + + while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) /* yield() */; + + SDHC_IRQSTAT = 0xffff; // clear interrupt status register +#if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA + SDHC_DSADDR = (LWord)pData; +#endif + SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(SDHC_BLOCK_SIZE); + #if defined(__IMXRT1052__) + SDHC_MIX_CTRL &= ~ SDHC_MIX_CTRL_DTDSEL; // write + SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; //DMA + #endif + sdhc_enableDma(); + // if multi-block write + // pre-erase blocks + if(count>1) + { + sdhc_CMD(SDHC_CMD55_XFERTYP, 0); + sdhc_CMD(SDHC_ACMD23_XFERTYP, count); + + SDHC_CMDARG = sector; + SDHC_XFERTYP = SDHC_CMD25_XFERTYP; + } + else + { + SDHC_CMDARG = sector; + SDHC_XFERTYP = SDHC_CMD24_XFERTYP; + } + +// SDHC_CMDARG = sector; +// SDHC_XFERTYP = (count==1) ? SDHC_CMD24_XFERTYP: SDHC_CMD25_XFERTYP; + +#if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_SWPOLL + if(sdhc_waitCommandReady()) + result = sdhc_WriteBlock(pData,count,SDHC_BLOCK_SIZE); + else + result=RES_WRITEERROR; +#elif SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA + result=RES_OK; +#endif + // Auto CMD12 is enabled for DMA + if((result != RES_OK) && (count>1)) + result=sdhc_CMD12_StopTransferWaitForBusy(); + +// wait for end of DMA + sdhc_DMAWait(); + + return result; +} + +int SDHC_ioctl(BYTE cmd, BYTE *buff) +{ + return RES_OK; +} +#endif + +#if defined(__MK20DX256__) // has no sdhc + int SDHC_disk_status(){ return RES_OK;} + int SDHC_disk_initialize(){ return RES_OK;} + int SDHC_disk_read(BYTE *buff, DWORD sector, UINT count){ return RES_OK;} + int SDHC_disk_write(const BYTE *buff, DWORD sector, UINT count){ return RES_OK;} + int SDHC_ioctl(BYTE cmd, BYTE *buff){ return RES_OK;} +#endif +#endif diff --git a/patches/sd_sdhc.zip b/patches/sd_sdhc.zip index 1450076c4a28dd4782fe5c71b616cc959d02833e..35626d88821878e324b8531a784cc6b1aff9099d 100644 GIT binary patch delta 8852 zcmV;FB5U3LOT@6aWAK2mql;=u|)dn!?Z}000x7u^7Pvf8!*bK$zc~eJHiX zFbt)(m*Xh*-DR*y_GT{$0rQHUG0bfmh`s`+G=P4b;=%krPWNVfU}F&EdUbPygA36> zt2JL0NUxG>7iLgM4I-53HVP&rjBak~m_`Vsqi;C{cezTj8M0J|6q={u zDw(+u#-YD1bsjS+CLa+N>AV818)OwM(zfEJ6c`NuOFuP2oQI{K z)Sd!--UkgZ1>YqQ{y=16L*8A{6rqFSq`O*-S<(Q=6!;_P>1W4yq1%q?T-qH}lvsYU z3ezoU8J@pb&B?dg3rG>}@PeEWx$)u!V9Q5;#9ocZev(XAA!1Mn!?K1J185x)t9eC? zI0knW{a4n=a#+7|M6S>Q$S96dNW2i31Qg^OOaIKk+DBv%r68;~dB^}Dn*b*Uuzy6% z#jO{DzmB}vgBaseegr;@*ub(!1G@pw0DgeNh>H{DVaWV=gL^uv(V;QQ>G@__~ zheuS5ib{|dDHH{IE7Z!M9*GWcmpuo}{-+Ox#I#o9RwabSN7gOOONyUOmM&un0oSnB z&0j`h<4{4`JSJsS7#wPt&y5o5`Z$%5_<*hR+dg(>j`(Xd96-)2An!Pmk7#xl=owWu z2Y{+MFrAV_5U%7Fr>;Xx@Ud=#h#X*lDHij@>k zg&34@4wMh;#P&HcHbBeb0Ohk4;^+!$SoACm)$bruLmNhiPO)hQ^{VDAy)h))QU|XU zlu}~~>l1tF`xDVhGk`alz@i{2wSiZkhSB(Ixi$2XRP*AA%>{V`bzM!hbXPZjY|S!9 zP+@g`OYj|monak>*(&g^!`~2yYiQkIyg?(9Oi*dvPsW|!soPY9?b=gF&-;LG!UG_4 zqADg#ggO=mQl|zzq8X<=8+Fw0EFQ+uYLS+SP_O1xV6~M%h4DOE zVju*~zAn3GkrSDd&=*2iKor-1oWSZB)}&iO+U}X3s?66n1E~OY=-PgIx=OBsNjj^q z&yj+-cL=bF&s(4nf^uk#3V}@s?~tXrfQUKu#(uqEki|wt-lHN}ludTx(PDbxu-Fj) za-3^yaua9+G$`gPh;QA@EpjY2c$+bleK+@k4JcKc@3%m>#bgM}Y`X1#pn>8QGi=aF zaqTo(IuO*7sUKf?LE4RC7`yF0&}zFJjHb6uru*d+oYpUAVRY?J9o!f0qYhC9+M8I}t8fWO`T<)`{Sh?2LA?9!7_ ze9~>BgM}o@vZq76%NI)-?bffNEmvtPKc-FbfAkTwwcbUAcKa8}4H3UWd;b^F*4tH^ z9Q-QU3a9-D|1s^kX;dsxdDsOf$U039f84nSMHq1=}Hi;RKBZF54KzF$%+|*k<3g zwKJ`a6tV{w!8#Rf@>+6I&_^V|uB(kM8B*;}KTP~ubwX?j#@|3fXP^A=13H)sSXJXn z9k++;&c4JAVGd!;VAX$xW9Mp4&mF0{i+n&4_f&S}edf8%rmi{)RcSZ8g92Xr8F;e5 zLm$rYn$7lqUi)K3v+bXq`L!~By$e#{cQ(+s60d%CW~UU)BJYmYE}*qYEn~>4zs$R| z-cY+>b<#lrwQ02!_e!B)Y+;7Xs8Mm3i|B8vc5&* zOAJEW`fSjrD9vWL^%;=~+1VNG;OEffpF?YvthYOVp7L|-+Euj2N)UWHw?91*(D(;9 z5wNlCn#0!Nj+h4(%(pvY$`wq7VzQvLBav2xNShNm!!zieXebpL`#WN`E0_nHhi6m9 zg@m2>DH-Wq_dt0^M!lXg>Oz&nYXME`yXrvg4bNO?rXY|J>n(D8Ox{YJZ7_eGkbl+X z`*s(9;pFXbNUN?uIrB3i7%NIfV@h)a!30X7<12`?r~YIoU~Y>L)3^ij&!JXj|kY|BYmZEtf9I z*Bf>7BhcQ^0fN_ClxMwlMC{MD3z9b#X-A*OP;p2zJJLmpq%Px~1+EzuG}6;rp#PO6 zQ#R?LY|}%bdbFAG>g^-4!V}<@I}X3PaTKM}uKFCT>!VckX-kz^y}9zFEVHgjfR{3V zVuCZR;13@@kXDP$JJ9PjX?4nISs(yBm~gCuz9g?mTOv(PYJE=9IgH(h_z!2y=<;G% zP|fOLc3N4=A%1F4z<&8A=-2bV``*1o6;Qv+J(zTV9jxkc(r1uUcNvBNmev22o@~%4^4%z!p^|XrSYQ6oNRkzkV%tp-qLyDTW`Bdi89#2iGFxf|(e&X1mlt~8yrEq`xkpAN(}QI5IuCb$5Fz-$ zl%z4b@a$598UqwU_$j5O&Ai2pFWj3hJ9D>rNX99SZHX|%{vu)B8EPMC&ZvmVhkr2Zj4T^>@4;Mu#Yf;_JE!P!7%=`bFW|*NS){5Xd_SowS@MI&-*A?k zN%30`W3oUS!Z(;AkAZVfj~4!kjAv)HnyBW3B<5B8H)a#D+n&#s$}WDV#;YJYykc|_ ztT4L#(RDP)oftREKtbuynPdMuf=A1z0~BYn$phC6tZT2JX07*q(hT# zwsQpk1=He`7FuzSIoB=_Yc05xqYH)Uh75b;_$H}9plQSaw&+pI zlLrGex_65?IpOy=@S0YJL(ef9o$WYTVJw>TGg?R10#wqI<~YwIwB1@CUNpA;?yb z;DbZhK4G`B!B=PxFMs4b27n?py5O*UTs~3j=J$#=2NDZhc}oCA7E~i161V#n5nvfW;aEKZZZ;r!&#VM0DE4B7znaA#bS7ZeK0VHO@HH;7Z zpD@^>V0ol2J-eEDekv5q+H`1y@GZ!j*|2*zUa;VT6t+O6A|$GD>xC;n;n%O&b^14u zgnh^+tgDvAkJH|T>Nu9jzx)xuwSmKSuh%sg%n9c?&zjhP&ZVv2dcKLXl)4*mb znU|*CcxDQfKGKu>IzZ9`iUv>I)Ru#fCWH>d0k<)Smg#&hfE_~N-8#&{i~+vhfE+WR ztfCV!g+=9my}dns$e1C%P99^$c$d=;8rr5uRWwAeD zR9R5Lz%};b2?VqRFEGx7$t0xjDR~PLiQ6{~g0BH35W;AxV&&xcVT^AajR6o}dO@0u zF9wPm9uz5UcpgXdW#~gV^dQ>=QH%|9`aTo<&ljkF_(l{g;_0xXr_eeT_YdlLTPFwz z-KvN0V{#zVU$0+_6)%(;Kdz89b6`V+?9{(q70JFb#Zyo`8+bfuUb{? z;)T(FG6iK51tnLhy{Z3PV^z?bU-@~us-m6*69d)yWffMTv?^bcqyr^-V?VL!s4VDj zi%wi@q#F&cxCm7v)hkv2A+QU5{OTEX_;OEqtSa5PBUHMw>${?lI|8zovJqv%6eBHN zad4E~YQ9bBDBqL_?zJ=yNvX60FQWWJ<;P}!D-5E57E?M~9Gq$pj}c-LK@7s1+_P1j zK8dC~I^DI!_=h*Mns^V5)b9fN<{sURht(OB=uZ*q+ozlm2B`TeOapdrl3u9ByN6Gb zP_>rAl=u%w;L2%J>3kxP3QK3^looT!@*P@91Qi63@&oiu{#p)l7%@AK>!jE2ugdp- zbevnN$_hAo=8W@IRmqrElS{~}e!M71fsu%^%3h$5&}F|-fIsRiDg!Ia9?5k3Gh=ab zQhbu0sS7pc_8G@E@=y}IPq0PKa*_5K6;_(;DWv#s4fs)iDgPGXz7w1#037RZ`v z&-|j|E2VB@+@+W*)^JEC7*zfM2bz z@xa3=pA;Ti#RsMM&^{>?F>6=#f6hBWEU2YewaJrbi9zY2|Ie}5n4T+E?ZSt-?7CRX z>~?-hvh|z$RW?5-E{l>yqw^rC2}fL;w3rFq>(C8-DEG(o`oH*gF*$LsD}Vv>A_E1_ zwcfE~Et&7a4Y{{kjsuka8Pcs=K=? z)PBYJ%3eL8PFV81(n~2D-R}8bN7<$1prsHh9iegsxH75=u>JxHrFlw!@7B;Ake~8< zF2O!-pOJ}|dbowj-pt9FSKsQX>ffNF|ML>)CEoOPcxDJZ{K)r$pV;+suCjgoBAloM zbFlh4+Wx8ONS%Ctu8Qesj(d7(*^b*Y2F9SC-R5Z0P2y~~u(oLfI9D`Vi$VGC;k?QA zK5K<-&O;h?I<)IYWJj$NE0jMTfLt#E8lMo(V3|a6D;n zO;$_%V;TuLkV*giZ-x$nEd=&H+k{w5gPT>HZ%bgF!>trp&&;EV-(ZMrC0P_vqWchx zI48p`ux6#Tt<-Ja!`{jG4Qu4?<$(TiiX#>-$}h=~diL%O{uKy+Vr#>Zam1288$$X= zTgD)ENdLl&I1WQ#@$w@jE?y_6=|HSnBKlq~o?!v_NVU|y;TV<;4Dihqh?&cXZUwS) zg@3nqtUYZc$+<+wFmIV#+*$aDB-_fS5?2e zXQqcolGDXnZN&6{ySlnwT~&R`6dWcpCG&(j!LzzJpM9K+P!+qH%@b7Qjo$+8ZLF{H z#VGj#T0MPX6(jb;s2NtusNZ|*PX|K*lxNvhm zqQ=a07-uCLfh*bgsa8^~chb?Vk6?SSE0R4RhGTUf;j{eq?uz3m$;&mLmq#_eL{77% zg2$>A7zF7LwPLysc&W#G+if_d7%e7bSVlp~YRkFfQmS$$&R%s3_`Bc$bQv_}sjAq2 zaG0+ptF^g*=8|q+LkcCY8Xa@aohf5)o`GErxB+wJV6G~bc! z+1io|X>Lb=h%T9!P^%W|GX7Sr*(Goep=dKUySA%;?d~6Xd#2l%&05V51?txwcpO{hc#->ec98M&zs!p))BhL3<{{<{b1X%KXg=QEt*|FBE_THN>` zC>xsA;P?f#K@y2g=<3ers9`pdHdhiRIzXv{8U`9m^STK%n2t}&NJRh9AP5S>P7Xj) zSC`v=GH`jh{RFNL%uVv16?@3OdMA#Oef@3_1HuQ*D~S)&?YFz#UaYek!D+ncEs&UP zh}i&4R&XQTL{r2OZPQ>rJsAxL!}Ek^g&HMrVJM@fiE)BvS(U-jhHv14{UNRu6+STu zq}_W3ClRon$Qomf?OSlXaSHJ$>w69X2Zk4B? z{ZHy%g*tS<|I)ketao8=hB9J)lCC6wCaD>vP#KxczI22mSdlcPr-jbR=>ELwh66EO64PASt)+l+N1X2 z_e`ZvNt{aQQ=->qtc@%cKh%8~V`s1&FW`#N(E-KKMU_C&6_%v9p8|X3%$59qs4#tW zS2#VEVVglp!EFBwPFKmr3)ns`&kJ`gI|rWUHdx>)VisWlylBAxMv7cWYy1qCbK-pI z$|IlJ5#eU=;;b!hEDDK)4}3{@?ynL`cHrCf4JKWPahTA+}WW zn_A)xVVil4iu6kqAM9 z-tVGc1BbfMQeJlzq`xq9yt=;B^pL^)j6h%G-c<8sI{O43{^ScePrzA!2$gJ$c33hT z1Uv}Y`dCn;;dB&FKzkg6Cx1=E?T9Voq~jfm>+ku47K!={UrW+eK9l-DUGgu>tVK~s zVxE?n&ZO21G9FURAxJ$`)k^0oJ#@*5JqL7)ZE)@G*rc|zv+aKCcs>bCG|v+rBT1}O zZA=E>?43FS9vuvGeG`9w_Ld*~lgqsf1f=&3b=*N1NH0xw>}-7D?x=Z)b$E~hgOu58 z8l=imS4HSY{G0Fepm)i*E?D1ohzoB-F-)AA@-(F%qQYCL*%&C zirbf$lkpHwFb3+3PZ@0xIBy$wT7kx$R?E3a@9dJ*#4^8_bvhn@%SyIcsA6ZPnX?gFGF)q>B~z(0C3&E(}_RtT1*Vb=lp;kaJu-ET#S>8VWMdM0v}&t z8>dW=oWirN>KGRL5i?k{dtLYosHwAe^{}n07jc2uKd7L^%V8;Y&g-w%@|{U7Lp~qE zPTwM%v@CMGCHFjk$M6`ozNU+rh;>MIM&p}K^Fksz2>i>~~df9pJQ_)Z^ za9Jf`zsZCiYqUXNyBKL=y^Qa0U>NAU=K8KZ3=C7?m-!4pD)=@O_$X0+7QuTe2wn)( zo`yl~X$m{YhT5$-K<>i_ju>J?>#2g4vUQMPnktDfaa1#r$R|{Uy3tYb5KJ@H#ChYM z+PfbOWXg+wtJ$S8K02P4fn2%aVau<(4vgvBNqhUChnWsCF?-j8*~QU4gJf8CoE(Ow zK(P$T3k$&&Ro~O`oGFcDPGJ@B`iw0E_BMBJ&g&AUIRzB%1G16u7&e85WG*31%(lf@ z0H`RN$$?`t5o7#jUC{aLgit9Jqq%CSVZFxy=gQxIcxA~aq004khN_jPLwR=&MKZFC ze3Yh5_fSaLCFfAMlG$x2GaC+d@Dtmvmdo7KL=EmH7XFm14j`O#iH`CU8aUTT%8qC`|0J5g76J-YrEjVLTS8`$hNqk|*V`>u%|PP%+rq zQZWgCD%fYx+Fh?b9NHBOo{U{YRf%g zA@V%d`>{e($h$`Ar&CGr#ydz3>_FO&*BVmjlzvfZ;u8--&Ich?ygQW&d`8Itg{jS` z=`PoWED1^>Ps7CkVq^h?w@;1afAm4SbT>YKz;$EE{P8CU-Uj~Mr(1ka!^WAp3IkmN zjF(1PorV3s(|>IUlM#DUmPQlKP2UQXFG^x?bQ$uj{2|jugGbN|6%bh2-1~zlYC% zOE_hnbSSf14B^%I8EyJy1_>S@x*Ut`z!GeRD`q`99cp@9{Vk=ksAc8Oh#1r(X;2re zWoe7I4xZ5ln^BYku?8!;(RXt&Kg0cVE5BgluJPOt@iQY4L^Ku&od{{YnG0AoOzRLK zxLxpQ2IM*lw`L8CfWe&`9`GeLZY5@ay+%Rs;M5qFZAvc24xt$rq9{Axf>s`wZ9%jM$+Zxrk<$Cfw7`%$!Uudb=!q-~nZ!z4vORYv#X{H$ zc!C8yW?qzP)U$EwYba7R(4-;O9SPsz(Ywa_dzdX#!QR#1$L4mgVtV;?QQq*DZ;0Zi zQ!GkW?Gj4?iM4 zxgXjFc_H}Vf2qN*xWi^2^YP8V(+^9uuOi)rmZXm{v%!R{Y@lvZyZFz4YnqIZ0L2LD zc|=l9p3>g%laWj$bh((8ldt!~BckgxLiYfYYVB!GL=;!aOUKjp=MzH;iHx1 zxT1&DF-VAH)v7g)ol`vg1ytZ7j~X)tnLq0*ZI9x)UJ`G##18Z~_kO0iwFMzgi2x#0 zw6$o8{}IY8jJJP(aM%N%E$VgqkpL5Q3!whQbovpwRw`qdyQG zi+z}(Pe+~K+dWU<6DQ?fjm8Ok0;5E!R*Oc-WN`g@Je<#11$KNF@U98jLIof`&*mQn zb2dlx(;V<;70!pW1UTI6TyOVw_Mtz1P{2sunT{H(Bt5c!0%a__z^k0+&l$s)n&8UH z5I`X4_IN=K#}#mWyB;T#QJIOgwN3JD8d}f-OD=c%^Ut6z_N7Dna{qx@<}~?eUBs;t zk$2$|XIkI2H0)z5yEj|m*%+P%MI_M3^kJ{P-zQGCBX6Mek6^PBTt)N#N9?cQVSu+F zcm);r6Kj8ei@={qycEDuF(X1u?QnXOS@a-5WSPC@$B@Cg%n-6DBh-sWggO1?#ekV; zV8(ex8t_u0yrTRdugEBgWsH}=z`I1*@Q+do+$4M~Z2sj)7oLJ6_BFBFm?<~}%Ot); zJKLQOKpv)Zxuc)Ujve4apT+gUEt47)Ij#NUHwSxvdz#dPq>G$f=?ak~3+--=RgxKz z%6Oueahi^_E`$%&e#@emAby0;l_-nW6Y^OCxKONK3YO}PVJTU`Db$G_loH2USPBVV z*?}oAp1hgGdnC-Jz^C*Ir-VJRkI)p`=qEBboQQh-oj8ekF&Vp}3#?@F6YTgG9N5>DigXMkTJq&M9H#{ z;N!J+6?%6@)e)hkVqGp@v>BtQrbTvI=H;S)9jzH1!6EneAPQ6$Wx=H@;bEwyA_y#) zbT*GRS+vTpk;kJsi`Mw6P95&fp#_7^jVul0&INgMDTOz4V~oa;ZH8*_)A4M0H6gRW za5`Gn*r|2PE>?Xbg~@6aWAK2mnxd$Wo-35dw-O002Opu^7Pvf0yGZ_T6Q$NcLtg z2?4W-o-xc>8eqNxg*1SEoVvmMK2G;$e86I0aJ{;@!9jyruGN~a3Zz%bwF|a{S&pBIR$sQO0gNTPlptmr{OA@xe%VAzbZ8y-)w=o&0|tk}P8Yn3H}4Cx7ts+&FuC z&FK{EQf`7I@fEG{vN%M^#7!o%aTz!PtGOWcEd>U{|I$y55a(g(C$*;lpZ7rnOu;7! zgf$SE*pN?GH1zABIO(nyW0nj6G6nt!divQhUg)-?I+u0_6(yFRtip5)T88H@R&(;L z_5wn`JG>w#L~guz0od{pv42(n)(1pMEr}w2@#IN*jR?DGmR+f;eQboqoNYzI|@aC z-U_ucs7Im$+-1)Jv;XNsfiSJrxK#;>Hjhae z6$XbI=5wQjx;{>2BtBs4{I-u>nIrxh4F`}53&=Z;kfl4os&c5riwb z#i{EM6MU@4AR-4?Vt)mHGiz+7rJMFeg_go;ftYiD62Or2vUx&@Zy^SynFD3PI}jOK%KGwA8_C0HxHJ!n(s=`u;?; z(hT5DCQ$4rr8e;D(=Zx;Ew_eVl4@Q&vAH0RpsuT_mhS3?t$$hO2r8$}ZwbC5ursW0 zFk1!Qb@&?saSg2-j5laRk_jrU`^mWTJ9V3iuw8o!>3JW}O?UugPE^H&iBQMFK zM>OMIi?Yd1JX%aI92OhmUygH)O>P2hfCfc+ z1@Wz$xkZk}25&QlvhU_TumPoN^ZgbGx0noJ`AoMHG=EUMVulSmDXyJHO9z5lGWFvt zFG#yl3}d(52U=~HgVFT1$#lPbg46otER3#Uai34|+EaMX`@kIMB_Yc|m^59MFX|Fh z_pzU@;svR5AgK`3_C#8F+(aYKncL{(5k+D&Sh6qBz$INB%U1G=1p)nPXz5u5xHMti z&t`w^8-Lg;LkAiwf=bFOnM~eueh_FQTott2R0KRkRgO`w{+U z?td3UP2nZa^gW9qJ~eC^tDfaU&lX`P?|C-W zo&4tcRM$MF=m;3OG+K=1tAH5*4?enWI5LMf$Mt14r}d z=EWWd0|eJP(^XZI$@ddn*=jQVbQlY^Lw~{v8Vg*uF^XdphEcK2zH4h|S{o^34=#dr zD%#|=)tsI?Qgs*kfFkax?8^JhbDK?Fbrh=7Zg>X;y!JEjWPyi1oZ&T_?SH-Y z$BJg#KRfelW&C;cNpl>B!{p`$6DVRmx9j#qJYmr*UkX3(~cWJ$$cEReTlLA$w zCa8`sU`p0DYf=1c#)eo=XZTMOut$cW*A=O=RR_>e6)F_;*@0z!i^i82gtqnBpifbn z&2Z~8A``N+Gupw=p~*jo)+$+VcYi$P=h(HYXpfa3_;hZ6dLp3l4{#!2W7{={t-~EL z4=R{%cf^z{mk|ari=>-JMmL8(!1_~ z@{WvpJ!RB|Du>qsn$~yKf!Z6MxzJ2OAS2dW}E7E`P$w+u@K_ zU4e4+FH(TUq}Ec%8`3`bA%lVxLKmLTFAE91sEVeYS%=6qdvGaet1cSc;h-R{W@|cB zjg(vd%yC@ED(+|qmcxm`v6@Z(l@aK#5$Kl**hWuc#Uq}DGxIA&0T5qEya~HddFB-4 zbro_78x*M5-%8Bvf64c6GkgGqFy`cjH zueT`Adh3YTpKTW;Zz|G`K98Z|kY;wIixf#+#=8hyGc0JNr?o);D@&$q(nHy%heGve zGvn3UM`VR3z%6$ies$w0N~K-(Iat?6sp!*|DzkcX3=#{)#IekAgAs!3;`^w|0_M&pi$(zSpb2nUT3{vVj;q-TuX_3 z$RvQV`zr@JF6${t+zqn+W3I{Lk6D2&s!Y&8#|0?_acF=2S`Y>0SBq5w%MkpP*~>*O zzh2D#28Awz)?tdUc@PR2wV|3x!r3N(y zD1`7+N=uu0iyL3KH(hq-Zu5|gQykk8VTk=j!n!lmKGK{~BRhP)lM*tF0;`!xMcA$_ zGEuFp+KCWsjTQ<5X<9as+Cgxs?&GdSy$yGI_ou4UW&3|~NFpx-xCf#i32>uJE#VIYc z;vRFZT_Dz4a4AO@3eyqubYu-nA&5P@dRx;wB?$0MQh`9zhyiTTqn0NR25NNg7ISjK z?{DBWtqg~rch-j&4YG(9xI2YE@GPl8@ZaqAj#MjDBK#yjKgF+MnkXzfc%hE**nflV z1WO>O^MBKbEMx!HUtrX@qnFUxIZZfAq9 z&>mj?$axF^MQU`xVfnaxqSnpt6>SbA7P#`30E#TAMm!{L_bnuX4hcrQgDA_TutA1w zl=&!b&`%z|qeANW6EutmZ0NL_k% zHS_#bD44bB&fk9Q<}I9sXq$yJmOjo?dplhUKEZ87+jn zvbMwR9(1?Qv5&?;AL5Y6_XJw9&15|y;1&N`yPm-+yq zP|GKGK{}p6w3-sUq@lF&Wri4UHrqHD<$o}p4OD>lSmM<(<*3)bX}X5D>am58ub+K&HQ5 zzZT0OI$oPYKi&jYnQuQC;VCQzOu{N&C^dduA#3Kqh6u|wV5FSFwNa$RJ7roOh-6Jc z&wP3%46l(Fv-T8Mg==?lqym`=h`8BFPQXMNB%ABv@}l#3WPo3_s@TN~qkm-z$|ed* zu2Oqb|GCDhpf|tr^K?~3JqacTs`bk%tU_s3z9dNpO7zBlV$)Gs(BBrFxY$TH8eDM^ zsz$0;tN=n_7y9_sGwSf=p7K~#x^qXUbY<6fMIUzrWG`hS%7iIKTDs!kD7)2so6=Ff zDG}UjX&jPLX$M|J`H9Mp&3{%HL;)?PbhbD+)gT@t#3X_kgg3cot2liUO?Py|9vZ3N1@w(Px*HFxGbquYBGk7}IUx*C^HrDz?A|23P>pvFpCqAbErluZACSP6 z)27n-L?9KG&dez-=9J|-w2}xa2q5JL=$rht9ON)!b{^MBuiamj?| z=c}rcF|8(-kXQY9QIG;75oMLVKp~;aexm??)LB#pR+c@I>Go&F;^d_GBt26XYRv63 zj&0#X%bCWqW?_UYa+OBzeFob`D}kC z*^0^A)XLKOws-cXEPr7m(asidKg>N+0g*2K_6titzOPZ>!V3c02$p0r5Ly*<#P26; zk@3s6Rq?|k_cq_a&o#u2uj28Mem`bgyMI&-B_f@~Hg#zY!y+t@HPxQ^Ma5S|-M$L* z7Zw~WTNDHIdVFSmNa@4L4@qHQ-Xzj~CX(1`d?L*}ial5WB7XtDT3_RVhf_W&JhX}r zO7Wq6QYd29uIm4scY;_@OR;K`C(jat(nbHDW3e$kSFGBF4|Cadv6k8G{E}qrH}|V- zeokB#C5uMqK~fWrxHf4q6S~)-8~RZ0kLmS)@$F)A;$Bw(1Lj2r3Z84dW5-%D-_K$A zWkV?pqP+%D=YPMBk4a0$RdSIwJu_1jsfa_RT9bjoz2!2zt;F(T4J7!zhLtZY#@K;& zy-4~sQKUjwQS&$CJ-giU$inn`0HjnZ>p*tWy<@a2IecV1H6EF2} z3zNN>lQXZr)l=2KK}Y}RCD2Q}>1*!H5P0~J?*%`x>*ZW!`}##VQ3>W?^>wuUQ`3<; z`TkrL)6pFF^wP2&w`UBDK|Q<8(WINi*=}KN(*|&^XtoxE^54UGlkI)h3fr8AH0pF} z`Cc60vVXm4_QV$8%0d79ivV+m`Vf!xeXNTPX~BpQll`3%T%zH4(%_n`miR|95^^Au z{`ubw9Rynl?0vQgv6u!ot2p15z&wXrDX^ZIM-#un5ZOwyD56C7AsBH^hFf6GN^4uG z+q{RplkpqY$lc2U{i72{EL@adk|Fi%-5dPt4u8bfh9l#MC4V-A^pCNOLF|zJ>(C|LxRN{QFjB)?L-z z)qfneH+B>gNgBEyd`pa=n>NPIy?eFSJ^te@C;9v@ zDBC}LS5)<+p;**loPqsQ^n5#8XWZgng?~8ZXZ6*2%d}VLBV4#SA5mjwI*hZD&A^px z{!%N+*E{Lx)<>{C*cHhh5W}&0i11l{dw0!ol;q`#&LUm>U2QNd&75)6X$hgvaR z2fWndgWVRKQj8W8GAyH@WVPkoaV1eX6KAiy1N>cZ0J;ns^AuFN&LZoB zWfLkww&5dSng8xVdKv^>2+D@0H8_4jZIDD_ z6S}(dIck_qq|KFti8fHGpoW3Q(yVR*4W{GsA`;QR*9d~bu#*9h#MNcC41Zi+WoFJLY488wjcf1T*e+#X(mx2*)w`RvC1fkui(tfm7Dc zhiAl=*7`*DXjXx7bwZ7ySZmCbSx9~sk5LDMFC$1sRES`5I<~yfkfjJ?{*4f_42Z|g zq2jof3Q@!b9&RB>PUm3gSJY_xk?tLRI+cp+=Sme`Cq0x_g`M47t$#v)Ptc-Jx5}eR z{SvBDeLYOUfDo4NMui`vU$_ps_>;nlsYBRZq$m*u7ZlAvP&9uIDDw4lU#04v>4dU% zD=UhjEHx~ae^#r`L?tXv(s-~ZCE?yX^AZ-&}oev(cj zDDVO8@idc;r;dUJ&42#Vu>R7pezHh^KLrn37nGJo@~P6bu(e0i!tbeimJ;%mo~5Ln z?N}RG>RPC7Fb>OLIbOo8o}+f@k?*c?g&4_B5X5=3z#^c z!RdN5dkNdeMQGt6Wv89Ko z^>{jhM-+BqbU3K5L(Sp5KnZO)_Lz8$Ba%&nw}yaC%^7KhH-wGmHA>RiPkgYq(Q;W% z-_rQt=rleUeSaQJaBk%74_<$9YO^v2I?$6Pxr%d-aE9%@4mt~Ps0-2mO-DicD?`ZZ zn=4JY?=LP0^cC)+v=~k2pTTXO91IsD@W4UM)uIlTxCBuILX15XG-og!#uHG<#^4@b z5y3EG%Q$g(kCO2R{`$j6eTJ_E>3^O|U!X2IZKc+t(0?8=Ps{dY(qjf04>9Htq#nv@ zr3;mFx!?qJ1G>dFxc2vKV%px@b-%Sep9ChF=LwIIBv-07M%X)hr;dO}-N6Lfcp?hk z@}qxnO2$AyD%L>99fW~&eN@NJ#ux76nT1%#M+q=Un7yW~sl;z(^eGeDvrBF+xujSuxuJ;owmnZk#1`#+39Lq*#xa-{#mze7cuA5MR(b&(415H z;))OfT%YP>;?KJl6T|U2KcLr+W}ip1@n|*}DSw*3#Ft9g#woiVr|_(+D#n_A!n6>r zZU_DXYU=D=HEipudHf0vk4k7pa#)I;Ncx+#d}mUtkR*q&)3?YvEsMNa$>+_n=7p`V z?qVilU7D>e93ZvEMgm0ayxHGujBwVG0g|{OBEp1gt__h!7(^POXI1~*|J?e3} z1bhx+!nJzh4n&V^$75}L(=rPpdY-JgrBkGRoR+nS|=Y@ z?U#sx&j_^26V^t-K))>4E$eZ>x_i?5BLVf&lgTHdp{Rggp)n6X2JcTR#zen+klCeSbcU;B5(l7Xr1dFsN-Mu!D4{-H8Kaz9!&^ zAvUzO6tt8zBNpK-eo2IhqnZ&!zDpw1jkXFhV4ATe&KsA%-updnoSN_J^K|TppuD3H(tt=hNyK^X#k!9qQG+w%gLdq@~hr*T2?n0T_ zaHxZy*><%|=B6fUa5uRi&^JV=27fBlXRnUBkl3#k6>BF4U~bziL+qZag0IVdVw1fu9upLNAwaa??{AKk_$Jc9X_w%ly%af%x*EnEaPXi=@%I! zc+}-;EVctnuo2cL}lpms!mXIQ1P>-ZRU9gsw9o{;4Mt_@ZMo|L9YOLs1 z-_8Ew0{73Y{F05k&J!xc&yDN~(O6_jBBb@E17OuKS3-o~cEO_=kgF)%nl&r}26t|F zz*pF~rI_^^1;K+;V_3E+=_uB%3sQ-dwq$$mPTqpB74WPDcz?{iC{?Sb9^OkRl;<{5TN*Z>FuxIh|b#J*ExalpI z18+FRqU4!fQZonM^p>lEx4h+Y;2MLNSu9IxR!P+yxK{U-YoKoU%GJQ@cCjpJe&7q9x=M7CpNPuF5NS2%6y#C%wJ1{T}8utI>k{!~PY9FTpG9yO1&O^d%vc;1aPE|F9SF+)j12%H&7T&NjXe}DLBMLDkMA#n^6B3ZR^g=6Ow4}T67 zIL}MLOhM*vKh+h!cWs2o-HDnnG=aG7IA!9vyeVXN!8> zeImd_-2$jTGo5}&9`F!Uhek0XzucEx>+Nl;%jge;oMInll+j81_g2>vW5h|hSEF$v zjDNr=QK(d+;b_voc{3g?=BxrczDsy4glwS#5MSntkNpLkBl>Cf`CA2-16l$cZg#GB zyL*SwA3rEyByUfLwFXI#tUwvdW_XqJ;ss;)QWIQT8vqCd-5xK=<+uc{Z#U!7WLRWk zZDpH0n+6uNz>>?I{`@njihXI*zC3&klz%x*K3WHHt3c#kxWt*(cP+R1*h-nrR(LUn z_cjp;G%|hMZ5{TAlkLeHDE%YYtOQrl{QD96OL!RIfdyVch1kT}-y+5)66yCjDy9Tu zsU1!Z=!zaCUMscN>~Jkuml>@Ur9@Tn;47!UtZ*w64a|_LNCRF%Kvk3-PZb#@v40Gw z5*T=&fENByN`c#ikGaji9O=UITExC4b{jLVg}<3Jb#5cvBOg0SPM)c!7Dv91;&#%vv`k$DGKb{$}zu|@Z!WrKcwVx$|RQrx#cmX zmecP3@t!z@exc1nH!bsW-j3Fdj^L2{dk_Vxi=yDtrSL%0LLLMbOgf!Mn=D!-t;pihoJDJVRi_U3 z=g@*dXU3L>ap#=8xsbq{xqmT6kd z?YyfuH$YZpa|8R;Y>t!R&V@LhagYDa?f=%PtY6&+H3&C!1a+5N*vRTN1?1kQ(pZK6 z{1;G50Rj{N6aWAK2mnxd$Wo-35dw-O002Op000R90000000031Ad?;@AO^7|00000 DC6UdO From 4823843807718c7e56b67fb925f054c30d110c19 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 9 Jul 2022 18:43:35 +0200 Subject: [PATCH 09/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- patches/sd_sdhc.c | 1228 -------------------------------------- 2 files changed, 1 insertion(+), 1229 deletions(-) delete mode 100644 patches/sd_sdhc.c diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index 0db09ab..e8530a4 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit 0db09ab6e925842407585158c5937c3729f34059 +Subproject commit e8530a45ab5b386aa05956eb368e856ab5c520d9 diff --git a/patches/sd_sdhc.c b/patches/sd_sdhc.c deleted file mode 100644 index 59aada5..0000000 --- a/patches/sd_sdhc.c +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * WMXZ Teensy uSDFS library - * Copyright (c) 2016 Walter Zimmer. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -// following code is modified by Walter Zimmer from -// from version provided by -// Petr Gargulak (NXP Employee) -//https://community.nxp.com/servlet/JiveServlet/download/339474-1-263510/SDHC_K60_Baremetal.ZIP -//see also -//https://community.nxp.com/thread/99202 - -#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) - -#include -#include -#include "core_pins.h" // include calls to kinetis.h or imxrt.h - -// for debugging in C -/* -#include "usb_serial.h" // for Serial -#include -void logg(char c) {usb_serial_putchar(c); usb_serial_flush_output();} -void logVar(char *str, uint32_t var) -{ char txt[80]; sprintf(txt,"%s: 0x%x\n",str,var); usb_serial_write(txt, strlen(txt)+1); usb_serial_flush_output();} -*/ -#include "../ff.h" -#include "../diskio.h" - -#include "sd_sdhc.h" -#include "sdio_priv.h" - - -/****************************************************************************** - Types -******************************************************************************/ -#ifdef OLD -/* Status of Disk Functions */ -typedef BYTE DSTATUS; - -/* Results of Disk Functions */ - -typedef enum { - RES_OK = 0, /* 0: Successful */ - RES_ERROR, /* 1: R/W Error */ - RES_WRPRT, /* 2: Write Protected */ - RES_NOTRDY, /* 3: Not Ready */ - RES_PARERR, /* 4: Invalid Parameter */ - RES_NONRSPNS, /* 5: No Response */ // from old diskio.h - RES_READERROR, /* 6: Read Error */ - RES_WRITEERROR /* 7: Write Error */ -} DRESULT; - -#endif - -enum { - SDHC_RESULT_OK = 0, /* 0: Successful */ - SDHC_RESULT_ERROR, /* 1: R/W Error */ - SDHC_RESULT_WRPRT, /* 2: Write Protected */ - SDHC_RESULT_NOT_READY, /* 3: Not Ready */ - SDHC_RESULT_PARERR, /* 4: Invalid Parameter */ - SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h -}; - -#define SDHC_STATUS_NOINIT 0x01 /* Drive not initialized */ -#define SDHC_STATUS_NODISK 0x02 /* No medium in the drive */ -#define SDHC_STATUS_PROTECT 0x04 /* Write protected */ - - -typedef struct { - uint8_t status; - uint8_t highCapacity; - uint8_t version2; - uint8_t tranSpeed; - uint32_t address; - uint32_t numBlocks; - uint32_t lastCardStatus; -} SD_CARD_DESCRIPTOR; - - -/****************************************************************************** - Private variables -******************************************************************************/ - -static SD_CARD_DESCRIPTOR sdCardDesc; - -/****************************************************************************** - Private functions -******************************************************************************/ - -uint8_t sd_CardInit(void); -int sd_CardReadBlocks(void * buff, uint32_t sector, uint32_t count); -int sd_CardWriteBlocks(const void * buff, uint32_t sector, uint32_t count); - -static int sd_CMD0_GoToIdle(void); -static int sd_CMD2_Identify(void); -static int sd_CMD3_GetAddress(void); -static int sd_ACMD6_SetBusWidth(uint32_t address, uint32_t width); -static int sd_CMD7_SelectCard(uint32_t address); -static int sd_CMD8_SetInterface(uint32_t cond); -static int sd_CMD9_GetParameters(uint32_t address); -static int sd_CMD16_SetBlockSize(uint32_t block_size); -//static int sd_CMD17_ReadBlock(uint32_t sector); -//static int sd_CMD24_WriteBlock(uint32_t sector); -static int sd_ACMD41_SendOperationCond(uint32_t cond); - -static int sd_CMD12_StopTransferWaitForBusy(void); -static int sd_CMD13_WaitForReady(uint32_t address); - -/****************************************************************************** - - Global functions - -******************************************************************************/ - -DSTATUS SDHC_disk_status() -{ return (DSTATUS) sdCardDesc.status; -} - -DSTATUS SDHC_disk_initialize() -{ return (DSTATUS) sd_CardInit(); -} - -DRESULT SDHC_disk_read(BYTE *buff, DWORD sector, UINT count) -{ return (DRESULT) sd_CardReadBlocks((void *) buff, (uint32_t) sector, (uint32_t) count); -} - -DRESULT SDHC_disk_write(const BYTE *buff, DWORD sector, UINT count) -{ return (DRESULT) sd_CardWriteBlocks((void *) buff, (uint32_t) sector, (uint32_t) count); -} - -DRESULT SDHC_disk_ioctl(BYTE cmd, BYTE *buff) -{ return RES_OK; -} - - - - -#define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN) - -/****************************************************************************** - local functions -******************************************************************************/ - -#if defined(__MK64FX512__) || defined(__MK66FX1M0__) - // initialize the SDHC Controller signals - static void sd_InitGPIO(void) - { - PORTE_PCR0 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D1 */ - PORTE_PCR1 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D0 */ - PORTE_PCR2 = PORT_PCR_MUX(4) | PORT_PCR_DSE; /* SDHC.CLK */ - PORTE_PCR3 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.CMD */ - PORTE_PCR4 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D3 */ - PORTE_PCR5 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D2 */ - } - - // release the SDHC Controller signals - static void sd_ReleaseGPIO(void) - { - PORTE_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D1 */ - PORTE_PCR1 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D0 */ - PORTE_PCR2 = 0; /* SDHC.CLK */ - PORTE_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.CMD */ - PORTE_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D3 */ - PORTE_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D2 */ - } - - static void initClock() - { - #ifdef HAS_KINETIS_MPU - // Allow SDHC Bus Master access. - MPU_RGDAAC0 |= 0x0C000000; - #endif - // Enable SDHC clock. - SIM_SCGC3 |= SIM_SCGC3_SDHC; - } - - static uint32_t sdClock() - { return F_CPU; - } - -#else - - static void sd_InitGPIO(void) - { - { //T4 // Inverted pins(T4) - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 0; //DAT2 - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 0; //DAT3 - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 0; //CMD - //3.3V - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 0; //CLK - //GND - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 0; //DAT0 - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 0; //DAT1 - - const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE | - IOMUXC_SW_PAD_CTL_PAD_DSE(1) | - IOMUXC_SW_PAD_CTL_PAD_SPEED(2); - - const uint32_t DATA_MASK = CLOCK_MASK | - (IOMUXC_SW_PAD_CTL_PAD_PUE | IOMUXC_SW_PAD_CTL_PAD_PUS(1)); - - IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK; - IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_05 = DATA_MASK; - IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 = DATA_MASK; - IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_01 = CLOCK_MASK; - IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_02 = DATA_MASK; - IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_03 = DATA_MASK; - } - } - - static void sd_ReleaseGPIO(void) - { - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 5; //GPIO3_IO16 - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 5; //GPIO3_IO17 - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 5; //GPIO3_IO12 - //3.3V - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 5; //GPIO3_IO13 - //GND - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 5; //GPIO3_IO14 - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 5; //GPIO3_IO15 - } - - static void initClock() - { - /* set PDF_528 PLL2PFD0 */ - CCM_ANALOG_PFD_528 |= (1 << 7); - CCM_ANALOG_PFD_528 &= ~(0x3F << 0); - CCM_ANALOG_PFD_528 |= ((24) & 0x3F << 0); // 12 - 35 - CCM_ANALOG_PFD_528 &= ~(1 << 7); - - /* Enable USDHC clock. */ - CCM_CCGR6 |= CCM_CCGR6_USDHC1(CCM_CCGR_ON); - CCM_CSCDR1 &= ~(CCM_CSCDR1_USDHC1_CLK_PODF_MASK); - // - // CCM_CSCMR1 &= ~(CCM_CSCMR1_USDHC1_CLK_SEL); // PLL2PFD2 - CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0 - CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); // &0x7 - - // for testing - CCM_CCOSR = CCM_CCOSR_CLKO1_EN | CCM_CCOSR_CLKO1_DIV(7) | CCM_CCOSR_CLKO1_SEL(1); //(1: SYS_PLL/2) - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 6; //CCM_CLKO1 (0 is USDHC1_DAT2) - // for testing - CCM_CCOSR |= (CCM_CCOSR_CLKO2_EN | CCM_CCOSR_CLKO2_DIV(7) | CCM_CCOSR_CLKO2_SEL(3)); //(3: usdhc1_clk_root)) - IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 6; //CCM_CLKO2 (0 is USDHC1_DAT3) - } - - static uint32_t sdClock() - { - uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1; - uint32_t PLL2PFD0 = (528000000U * 3) / ((CCM_ANALOG_PFD_528 & 0x3F) / 6) / divider; - return PLL2PFD0; - } - -#endif - -static void setSdclk(uint32_t kHzMax) { - const uint32_t DVS_LIMIT = 0X10; - const uint32_t SDCLKFS_LIMIT = 0X100; - uint32_t dvs = 1; - uint32_t sdclkfs = 1; - uint32_t maxSdclk = 1000 * kHzMax; - - // uint32_t f_pll = F_CPU; - uint32_t f_pll = sdClock(); - - while ((f_pll / (sdclkfs * DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) { - sdclkfs <<= 1; - } - while ((f_pll / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) { - dvs++; - } - // unused // uint32_t m_sdClkKhz = f_pll / (1000 * sdclkfs * dvs); - - sdclkfs >>= 1; - dvs--; - - #if defined(__MK64FX512__) || defined(__MK66FX1M0__) - // Disable SDHC clock. - SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN; - #endif - - // Change dividers. - uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK - | SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK); - - SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs) - | SDHC_SYSCTL_SDCLKFS(sdclkfs); - - // Wait until the SDHC clock is stable. - while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) { } - - #if defined(__MK64FX512__) || defined(__MK66FX1M0__) - // Enable the SDHC clock. - SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN; - #endif -} - - -/****************************************************************************** - - SDHC functions - -******************************************************************************/ - -static volatile uint32_t dmaDone=0; -// - -void sd_isr(void) -{ SDHC_IRQSIGEN &= ~SDHC_IRQSIGEN_DMA_MASK; - // - while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC));// SDHC_IRQSTAT &= ~SDHC_IRQSTAT_TC; - - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) - SDHC_MIX_CTRL &= ~(SDHC_MIX_CTRL_AC23EN | SDHC_MIX_CTRL_DMAEN) ; - #endif - - if(SDHC_SYSCTL & SDHC_SYSCTL_HCKEN) SDHC_SYSCTL &= ~SDHC_SYSCTL_HCKEN; - SDHC_PROCTL &= ~SDHC_PROCTL_D3CD; SDHC_PROCTL |= SDHC_PROCTL_D3CD; - - dmaDone=1; -} - -// initialize the SDHC Controller -// returns status of initialization(OK, nonInit, noCard, CardProtected) -static uint8_t sd_Init(void) -{ - initClock(); - - // De-init GPIO - to prevent unwanted clocks on bus - sd_ReleaseGPIO(); - #if defined (__IMXRT1052__) || defined (__IMXRT1062__) - SDHC_SYSCTL |= 0xF; - SDHC_MIX_CTRL |= 0x80000000; - #endif - - /* Reset SDHC */ - SDHC_SYSCTL |= SDHC_SYSCTL_RSTA | SDHC_SYSCTL_SDCLKFS(0x80); - while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) ; // wait - - /* Set the SDHC initial baud rate divider and start */ - setSdclk(400); - - /* Poll inhibit bits */ - while (SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB)) ; - - /* Init GPIO again */ - sd_InitGPIO(); - - /* Initial values */ // to do - Check values -// SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512); - - SDHC_PROCTL &= ~SDHC_PROCTL_DMAS(3); // clear ADMA - - SDHC_PROCTL |= SDHC_PROCTL_D3CD; - // SDHC_PROCTL = SDHC_PROCTL_EMODE(SDHC_PROCTL_EMODE_INVARIANT) | SDHC_PROCTL_D3CD; - // SDHC_WML |= SDHC_WML_RDWML(SDHC_FIFO_BUFFER_SIZE) | SDHC_WML_WRWML(SDHC_FIFO_BUFFER_SIZE); - - #if defined(__IMXRT1052__) || defined (__IMXRT1062__) - SDHC_VENDOR = 0x2000F801; // (1<<29 | 0x1F<<11 | 1); - SDHC_VENDOR2 &= ~(1<<12); //switch off ACMD23 sharing SDMA - #endif - - // clear interrupt status - SDHC_IRQSTAT = SDHC_IRQSTAT; - - /* Enable requests */ - SDHC_IRQSTATEN = SDHC_IRQSTAT_CRM | SDHC_IRQSTATEN_CIESEN | - SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; - - attachInterruptVector(IRQ_SDHC, sd_isr); - NVIC_SET_PRIORITY(IRQ_SDHC, 6 * 16); - NVIC_ENABLE_IRQ(IRQ_SDHC); - - // initial clocks... SD spec says only 74 clocks are needed, but if Teensy rebooted - // while the card was in middle of an operation, thousands of clock cycles can be - // needed to get the card to complete a prior command and return to a usable state. - for (int ii = 0; ii < 500; ii++) { - SDHC_SYSCTL |= SDHC_SYSCTL_INITA; - while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) ; - } - - if(!(SDHC_PRSSTAT & SDHC_PRSSTAT_CINS)) return SDHC_STATUS_NODISK; - return 0; -} - -uint8_t SDHC_GetCardType(void) -{ - if (sdCardDesc.status) return 0; - if (sdCardDesc.version2 == 0) return 1; // SD_CARD_TYPE_SD1 - if (sdCardDesc.highCapacity == 0) return 2; // SD_CARD_TYPE_SD2 - return 3; // SD_CARD_TYPE_SDHC -} - -//----------------------------------------------------------------------------- -// initialize the SDHC Controller and SD Card -// returns status of initialization(OK, nonInit, noCard, CardProtected) -uint8_t sd_CardInit(void) -{ - uint8_t resS; - int resR; - - resS = sd_Init(); - - sdCardDesc.status = resS; - sdCardDesc.address = 0; - sdCardDesc.highCapacity = 0; - sdCardDesc.version2 = 0; - sdCardDesc.numBlocks = 0; - - if (resS) return resS; - - SDHC_IRQSIGEN = 0; - #if defined (__IMXRT1052__) || defined(__IMXRT1062__) - uint32_t mixCtrl = 0x80000000; //SDHC_MIX_CTRL; - // mixCtrl |= SDHC_MIX_CTRL_BCEN; // does not hurt - // mixCtrl |= SDHC_MIX_CTRL_DTDSEL; // write/read (will be set later - // mixCtrl |= SDHC_MIX_CTRL_MSBSEL; //for multi block transfer - // mixCtrl |= SDHC_MIX_CTRL_AC12EN; //for multi block transfer - // mixCtrl |= SDHC_MIX_CTRL_AC23EN; - SDHC_MIX_CTRL = mixCtrl; - #endif - - resR = sd_CMD0_GoToIdle(); - if (resR) { return sdCardDesc.status = SDHC_STATUS_NOINIT;} - resR = sd_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern - if (resR == SDHC_RESULT_OK) - { if (!((SDHC_CMDRSP0 & 0x000001AA)== 0x000001AA)) return sdCardDesc.status = SDHC_STATUS_NOINIT; - sdCardDesc.highCapacity = 1; - } - else if (resR == SDHC_RESULT_NO_RESPONSE) - { // version 1 cards do not respond to CMD8 - } - else return sdCardDesc.status = SDHC_STATUS_NOINIT; - - if (sd_ACMD41_SendOperationCond(0)) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - if (SDHC_CMDRSP0 & 0x300000) { - uint32_t condition = 0x00300000; - if (sdCardDesc.highCapacity) condition |= 0x40000000; - // - uint32_t ii = 0; - do { - ii++; - if (sd_ACMD41_SendOperationCond(condition)) { - resS = SDHC_STATUS_NOINIT; - break; - } - } while ((!(SDHC_CMDRSP0 & 0x80000000)) && (ii < SDHC_INITIALIZATION_MAX_CNT)); - - if (resS) return resS; - - if ((ii >= SDHC_INITIALIZATION_MAX_CNT) || (!(SDHC_CMDRSP0 & 0x40000000))) - sdCardDesc.highCapacity = 0; - } - - // Card identify - SDHC_CMDRSP0=SDHC_CMDRSP1=SDHC_CMDRSP2=SDHC_CMDRSP3=0; - if (sd_CMD2_Identify()) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - // Get card address - if (sd_CMD3_GetAddress()) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - sdCardDesc.address = SDHC_CMDRSP0 & 0xFFFF0000; - - - // Get card parameters - if (sd_CMD9_GetParameters(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - if (!(SDHC_CMDRSP3 & 0x00C00000)) { - uint32_t read_bl_len, c_size, c_size_mult; - - read_bl_len = (SDHC_CMDRSP2 >> 8) & 0x0F; - c_size = SDHC_CMDRSP2 & 0x03; - c_size = (c_size << 10) | (SDHC_CMDRSP1 >> 22); - c_size_mult = (SDHC_CMDRSP1 >> 7) & 0x07; - sdCardDesc.numBlocks = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << (read_bl_len - 9)); - } else { - uint32_t c_size; - sdCardDesc.version2 = 1; - c_size = (SDHC_CMDRSP1 >> 8) & 0x003FFFFF; - sdCardDesc.numBlocks = (c_size + 1) << 10; - } - - // Select card - if (sd_CMD7_SelectCard(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - // Set 512 Block size in SD card - if (sd_CMD16_SetBlockSize(SDHC_BLOCK_SIZE)) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - // Set 4 bit data bus width - if (sd_ACMD6_SetBusWidth(sdCardDesc.address, 2)) return sdCardDesc.status = SDHC_STATUS_NOINIT; - - // Set Data bus width also in SDHC controller - SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK; - SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); -// SDHC_PROCTL |= SDHC_PROTCT_BURST_LENEN(7); - - // De-Init GPIO - sd_ReleaseGPIO(); - - // Set the SDHC default baud rate - setSdclk(60000); - // SDHC_SetClock(SDHC_SYSCTL_25MHZ); - // TODO: use CMD6 and CMD9 to detect if card supports 50 MHz - // then use CMD4 to configure card to high speed mode, - // and SDHC_SetClock() for 50 MHz config - - // Init GPIO - sd_InitGPIO(); - - return sdCardDesc.status; -} - - -//----------------------------------------------------------------------------- -// FUNCTION: sd_CardReadBlock (disk_read) -// SCOPE: SDHC public related function -// DESCRIPTION: Function read block to disk -// -// PARAMETERS: buff - pointer on buffer where read data should be stored -// sector - index of sector -// count - number of secorts -// -// RETURNS: result of operation -//----------------------------------------------------------------------------- -#define SDHC_CMD17_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD17) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ - | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN | SDHC_XFERTYP_DTDSEL) -#define SDHC_CMD18_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD18) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ - | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN | SDHC_XFERTYP_DTDSEL \ - | SDHC_XFERTYP_AC12EN| SDHC_XFERTYP_BCEN | SDHC_XFERTYP_MSBSEL ) -// -int sd_CardReadBlocks(void * buff, uint32_t sector, uint32_t count) -{ - int result=0; - // unused // uint32_t* pData = (uint32_t*)buff; - - - // Convert LBA to BYTE address if needed - if (!sdCardDesc.highCapacity) sector *= 512; - - // Check if this is ready - if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; - - while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) ; - - // clear status - SDHC_IRQSTAT = SDHC_IRQSTAT; - - // use dma: disabling polling - uint32_t irqstat = SDHC_IRQSTATEN; - irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; - irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; - // enable status - irqstat |= /*SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN |*/ SDHC_IRQSTATEN_DMAESEN ; - irqstat |= SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ;//| SDHC_IRQSTATEN_CCSEN ; - SDHC_IRQSTATEN = irqstat; - - uint32_t sigen = SDHC_IRQSIGEN; - sigen |= SDHC_IRQSIGEN_DMA_MASK ; - SDHC_IRQSIGEN = sigen; - - SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) - - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL ; // read - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; // DMA - SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_BCEN; // Block Count - SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_MSBSEL; //for multi block transfer - SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_AC12EN; //for multi block transfer - if(count>1) - { - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_BCEN; // Block Count - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_MSBSEL; //for multi block transfer - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_AC12EN; //for multi block transfer - } - #endif - SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); - - // enable DMA - dmaDone=0; - SDHC_DSADDR = (uint32_t)buff; - -#if defined(__IMXRT1062__) - if((uint32_t)buff >= 0x20200000U) - arm_dcache_flush_delete((void *)buff, 512 * count); -#endif - - // send command - SDHC_CMDARG = sector; - SDHC_XFERTYP = count==1 ? SDHC_CMD17_XFERTYP: SDHC_CMD18_XFERTYP; - - // wait for DMA - while(!dmaDone); - SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); - -#if defined(__IMXRT1062__) - if((uint32_t)buff >= 0x20200000U) - arm_dcache_flush_delete((void *)buff, 512 * count); -#endif - - // Auto CMD12 is enabled for DMA so call it if DMA error - if((SDHC_DSADDR < (uint32_t)(buff+(count*512))) && (count>1)) - result=sd_CMD12_StopTransferWaitForBusy(); - - return result; -} - -//----------------------------------------------------------------------------- -// FUNCTION: sd_CardWriteBlock (disk_write) -// SCOPE: SDHC public related function -// DESCRIPTION: Function write block to disk -// -// PARAMETERS: buff - pointer on buffer where is stored data -// sector - index of sector -// -// RETURNS: result of operation -//----------------------------------------------------------------------------- -#define SDHC_CMD24_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD24) |SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ - | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN) - //| SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN | SDHC_XFERTYP_MSBSEL - -#define SDHC_CMD25_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD25) |SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) \ - | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN \ - | SDHC_XFERTYP_AC12EN| SDHC_XFERTYP_BCEN | SDHC_XFERTYP_MSBSEL ) -// -int sd_CardWriteBlocks(const void * buff, uint32_t sector, uint32_t count) -{ - int result=0; - void *buff2 = NULL; - // unused // const uint32_t *pData = (const uint32_t *)buff; - - // Convert LBA to uint8_t address if needed - if (!sdCardDesc.highCapacity) sector *= 512; - - // Check if this is ready - if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; - - while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) ; - - // clear status - SDHC_IRQSTAT = SDHC_IRQSTAT; - - uint32_t irqstat = SDHC_IRQSTATEN; - // use dma: disabling polling - irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; - irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; - // enable status - irqstat |= SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN | SDHC_IRQSTATEN_DMAESEN ; - irqstat |= SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ;//| SDHC_IRQSTATEN_CCSEN ; - SDHC_IRQSTATEN = irqstat; - - uint32_t sigen = SDHC_IRQSIGEN; - sigen |= SDHC_IRQSIGEN_DMA_MASK ; - SDHC_IRQSIGEN = sigen; - - SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) - SDHC_MIX_CTRL &= ~ SDHC_MIX_CTRL_DTDSEL; // write - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; //DMA - SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_BCEN; // Block Count - SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_MSBSEL; //for multi block transfer - SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_AC12EN; //for multi block transfer - if(count>1) - { - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_BCEN; // Block Count - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_MSBSEL; //for multi block transfer - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_AC12EN; //for multi block transfer - } - #endif - SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); - - if((uint32_t)buff % 4) { - if((buff2 = malloc(512 * count))) - buff = memcpy(buff2, buff, 512 * count); - } - -#if defined(__IMXRT1062__) - if((uint32_t)buff >= 0x20200000U) - arm_dcache_flush_delete((void *)buff, 512 * count); -#endif - - // enable DMA - dmaDone=0; - SDHC_DSADDR = (uint32_t)buff; - // - // send write command - SDHC_CMDARG = sector; - SDHC_XFERTYP = count==1 ? SDHC_CMD24_XFERTYP: SDHC_CMD25_XFERTYP; - // - // wait for DMA to finish - while(!dmaDone); - - SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); - while(SDHC_PRSSTAT & SDHC_PRSSTAT_DLA); - - //check for SD status (if data are written?) - result = sd_CMD13_WaitForReady(sdCardDesc.address); - - if(buff2) - free(buff2); - - // Auto CMD12 is enabled for DMA so call it when transfer error - if((result != SDHC_RESULT_OK) && (count>1)) - result=sd_CMD12_StopTransferWaitForBusy(); - - return result; -} - -/****************************************************************************** - - Private functions - -******************************************************************************/ -// waits for status bits sets -static uint32_t sd_WaitStatus(uint32_t mask) -{ - uint32_t result; - uint32_t timeout = 1 << 24; - do - { result = SDHC_IRQSTAT & mask; - timeout--; - } while (!result && (timeout)); - if (timeout) return result; - return 0; -} - -/***************************** LOW Level SDHC interface ********************************/ -// sends the command to SDcard -static int sd_CMD(uint32_t xfertyp, uint32_t arg) -{ - // Card removal check preparation - SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM; - - // Wait for cmd line idle // to do timeout PRSSTAT[CDIHB] and the PRSSTAT[CIHB] - while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)); - - // send command - SDHC_CMDARG = arg; - SDHC_XFERTYP = xfertyp; - - /* Wait for response */ - const uint32_t mask = SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE | SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CC; - if (sd_WaitStatus(mask) != SDHC_IRQSTAT_CC) - { SDHC_IRQSTAT |= mask; - return SDHC_RESULT_ERROR; - } - return SDHC_RESULT_OK; - - /* Check card removal */ - if (SDHC_IRQSTAT & SDHC_IRQSTAT_CRM) - { SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC; - return SDHC_RESULT_NOT_READY; - } - - /* Get response, if available */ - if (SDHC_IRQSTAT & SDHC_IRQSTAT_CTOE) - { SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC; - return SDHC_RESULT_NO_RESPONSE; - } - SDHC_IRQSTAT |= SDHC_IRQSTAT_CC; - - return SDHC_RESULT_OK; -} - -// send CMD 55 Application specific command -#define SDHC_CMD55_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD55) | SDHC_XFERTYP_CICEN | \ - SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) - -static int sd_ACMD(uint32_t xfertyp, uint32_t arg1, uint32_t arg2) -{ - int result =sd_CMD(SDHC_CMD55_XFERTYP,arg1); - if(!(result == SDHC_RESULT_OK)) return result; - return sd_CMD(xfertyp,arg2); -} - -/* - * Convenience interfaces - */ -// ---------- sends CMD0 to put SDCARD to idle -#define SDHC_CMD0_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD0) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_NO)) -// -static int sd_CMD0_GoToIdle(void){ return sd_CMD(SDHC_CMD0_XFERTYP,0); } - -// ---------- sends CMD2 to identify card -#define SDHC_CMD2_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD2) | SDHC_XFERTYP_CCCEN \ - | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136)) -// -static int sd_CMD2_Identify(void){ return sd_CMD(SDHC_CMD2_XFERTYP,0); } - -// ---------- sends CMD 3 to get address -#define SDHC_CMD3_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD3) | SDHC_XFERTYP_CICEN | \ - SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) -// -static int sd_CMD3_GetAddress(void){ return sd_CMD(SDHC_CMD3_XFERTYP,0); } - - -// ---------- sends ACMD6 to set bus width -#define SDHC_ACMD6_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_ACMD6) | SDHC_XFERTYP_CICEN | \ - SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) -// -static int sd_ACMD6_SetBusWidth(uint32_t address, uint32_t width) -{ return sd_ACMD(SDHC_ACMD6_XFERTYP,address, width); } - - -// ---------- sends CMD 7 to select card -#define SDHC_CMD7_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD7) | SDHC_XFERTYP_CICEN | \ - SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48BUSY)) -// -static int sd_CMD7_SelectCard(uint32_t address){ return sd_CMD(SDHC_CMD7_XFERTYP, address);} - -// ---------- CMD8 to send interface condition -#define SDHC_CMD8_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD8) | SDHC_XFERTYP_CICEN | \ - SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) -// -static int sd_CMD8_SetInterface(uint32_t cond){ return sd_CMD(SDHC_CMD8_XFERTYP, cond); } - -// ---------- sends CMD 9 to get interface condition -#define SDHC_CMD9_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD9) | SDHC_XFERTYP_CCCEN | \ - SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136)) -// -static int sd_CMD9_GetParameters(uint32_t address) -{ - int result = sd_CMD(SDHC_CMD9_XFERTYP, address); - if (result == SDHC_RESULT_OK) { sdCardDesc.tranSpeed = SDHC_CMDRSP2 >> 24;} - return result; -} - -// ---------- sends CMD12 to stop transfer -#define SDHC_CMD12_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD12) | SDHC_XFERTYP_CMDTYP(SDHC_XFERTYP_CMDTYP_ABORT) | \ - SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48BUSY)) -// -static int sd_CMD12_StopTransfer(void){ return sd_CMD(SDHC_CMD12_XFERTYP, 0);} - -// ---------- sends CMD12 to stop transfer and first waits to ready SDCard -static int sd_CMD12_StopTransferWaitForBusy(void) -{ - uint32_t timeOut = 1000; - int result; - do - { result = sd_CMD12_StopTransfer(); - timeOut--; - } while (timeOut && (SDHC_PRSSTAT & SDHC_PRSSTAT_DLA) && result == SDHC_RESULT_OK); - - if (result != SDHC_RESULT_OK) return result; - if (!timeOut) return SDHC_RESULT_NO_RESPONSE; - - return SDHC_RESULT_OK; -} - -// ---------- sends CMD13 to check uSD status -#define SDHC_CMD13_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD13) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) -// -static int sd_CMD13_Check_Status(uint32_t address){ return sd_CMD(SDHC_CMD13_XFERTYP, address);} - -#define CARD_STATUS_READY_FOR_DATA (1UL << 8) -// ---------- sends CMD13 to check uSD status and wait for ready -static int sd_CMD13_WaitForReady(uint32_t address) -{ int result; - do - { while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) ; - SDHC_IRQSTATEN |= SDHC_IRQSTATEN_CCSEN; - SDHC_IRQSTAT=SDHC_IRQSTAT; - // CMD13 to check uSD status - result = sd_CMD13_Check_Status(sdCardDesc.address); - if (result != SDHC_RESULT_OK) return result; - } while(!((SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA)==CARD_STATUS_READY_FOR_DATA)); // while data? - return SDHC_RESULT_OK; -} - -// ---------- sends CMD16 to set block size -#define SDHC_CMD16_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_CMD16) | SDHC_XFERTYP_CICEN | \ - SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) -// -static int sd_CMD16_SetBlockSize(uint32_t block_size){ return sd_CMD(SDHC_CMD16_XFERTYP, block_size);} - -// ---------- ACMD 41 to send operation condition -#define SDHC_ACMD41_XFERTYP (SDHC_XFERTYP_CMDINX(SDHC_ACMD41) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)) -// -static int sd_ACMD41_SendOperationCond(uint32_t cond){ return sd_ACMD(SDHC_ACMD41_XFERTYP,0, cond);} - - -#endif // __MK64FX512__ or __MK66FX1M0__ or __IMXRT1052__ or __IMXRT1062__ - - - - - - - - - - - - - - -#ifdef XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -#if defined(__MK66FX1M0__) || defined (__MK64FX512__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) -#include "sd_defs.h" -#include "sd_sdhc.h" - -#include "sdio.h" -#include "sdio_priv.h" - -#define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN) -SD_CARD_DESCRIPTOR sdCardDesc; - -int SDHC_disk_status() -{ - return sdCardDesc.status; -} - -int SDHC_disk_initialize() -{ - DSTATUS resS; - - uint32_t kbaudrate; - - resS = sdhc_Init(); - - sdCardDesc.status = resS; - sdCardDesc.address = 0; - sdCardDesc.highCapacity = 0; - sdCardDesc.version2 = 0; - sdCardDesc.numBlocks = 0; - - if(resS) return resS; - if(!sdhc_CMD(SDHC_CMD0_XFERTYP, 0)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD0); - - if(sdhc_CMD(SDHC_CMD8_XFERTYP, 0X1AA)) // 3.3V and AA check pattern - { - if (SDHC_CMDRSP0 != 0X1AA) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD8); - sdCardDesc.version2 = 1; - } - - uint32_t arg = sdCardDesc.version2 ? 0X40300000 : 0x00300000; - int ii = SDHC_INITIALIZATION_MAX_CNT; - do { - if(!(sdhc_CMD(SDHC_CMD55_XFERTYP,0) && sdhc_CMD(SDHC_ACMD41_XFERTYP,arg)) || !ii ) - SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_ACMD41); - } while ((SDHC_CMDRSP0 & 0x80000000) == 0 && ii--); - - m_sdhc_ocr = SDHC_CMDRSP0; - if (SDHC_CMDRSP0 & 0x40000000) - { // is high capacity - sdCardDesc.highCapacity = 1; - } - - // Card identify - if(!sdhc_CMD(SDHC_CMD2_XFERTYP,0)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD2); - - // Get card address - if(!sdhc_CMD(SDHC_CMD3_XFERTYP,0)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD3); - - sdCardDesc.address = SDHC_CMDRSP0 & 0xFFFF0000; - - // Get card parameters - if(!sdhc_CMD(SDHC_CMD9_XFERTYP,sdCardDesc.address)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD9); - if (0 == (SDHC_CMDRSP3 & 0x00C00000)) - { - LWord read_bl_len, c_size, c_size_mult; - - read_bl_len = (SDHC_CMDRSP2 >> 8) & 0x0F; - c_size = SDHC_CMDRSP2 & 0x03; - c_size = (c_size << 10) | (SDHC_CMDRSP1 >> 22); - c_size_mult = (SDHC_CMDRSP1 >> 7) & 0x07; - sdCardDesc.numBlocks = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << (read_bl_len - 9)); - } - else - { - LWord c_size; - - sdCardDesc.version2 = 1; - c_size = (SDHC_CMDRSP1 >> 8) & 0x003FFFFF; - sdCardDesc.numBlocks = (c_size + 1) << 10; - } - - if(!sdhc_CMD(SDHC_CMD10_XFERTYP,sdCardDesc.address)) {SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD10);} - else - { uint8_t d[16]; - d[0] = SDHC_CMDRSP3 >> 16; - d[1] = SDHC_CMDRSP3 >> 8; - d[2] = SDHC_CMDRSP3; - d[3] = SDHC_CMDRSP2 >> 24; - d[4] = SDHC_CMDRSP2 >> 16; - d[5] = SDHC_CMDRSP2 >> 8; - d[6] = SDHC_CMDRSP2; - d[7] = SDHC_CMDRSP1 >> 24; - d[8] = SDHC_CMDRSP1 >> 16; - d[9] = SDHC_CMDRSP1 >> 8; - d[10] = SDHC_CMDRSP1; - d[11] = SDHC_CMDRSP0 >> 24; - d[12] = SDHC_CMDRSP0 >> 16; - d[13] = SDHC_CMDRSP0 >> 8; - d[14] = SDHC_CMDRSP0; - d[15] = 0; - } // function not used yet - -logg('h'); - // Select card - if(!sdhc_CMD(SDHC_CMD7_XFERTYP,sdCardDesc.address)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD7); - -logg('j'); - // Set Block Size to 512 - // Block Size in SDHC Controller is already set to 512 by SDHC_Init(); - // Set 512 Block size in SD card - if(!sdhc_CMD(SDHC_CMD16_XFERTYP,SDHC_BLOCK_SIZE)) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_CMD16); - -logg('k'); - if(SDHC_DO4BITS) - { - // Set 4 bit data bus width - if(!(sdhc_CMD(SDHC_CMD55_XFERTYP,sdCardDesc.address) && sdhc_CMD(SDHC_ACMD6_XFERTYP,2))) SDHC_ERROR(STA_NOINIT, SD_CARD_ERROR_ACMD6); - - // Set Data bus width also in SDHC controller - SDHC_PROCTL &= (~ SDHC_PROCTL_DTW_MASK); - SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); - } -logg('l'); - -#if defined(__MK66FX1M0__) || defined (__MK64FX512__) - #if SDHC_USE_ISR == 1 - // adapted from Bill Greiman - // but he has last condition wrong (following section 60.7.4.2 in K66P144M180SF5RMV2.pdf) - if(sdhc_CMD6_Switch(0X00FFFFF1,m_sdhc_CMD6_Status) && (m_sdhc_CMD6_Status[13] & 2) && - sdhc_CMD6_Switch(0X80FFFFF1,m_sdhc_CMD6_Status) && !((m_sdhc_CMD6_Status[16] & 0xF) == 0xf)) - kbaudrate = 60000; - else - kbaudrate = 25000; - #else - kbaudrate = 50000; - #endif -#else - kbaudrate = 50000; -#endif -/* - // De-Init GPIO - sdhc_InitGPIO(3); - - // Set the SDHC default baud rate - sdhc_SetBaudrate(kbaudrate); - - // Init GPIO - sdhc_InitGPIO(0xFFFF); -*/ -logg('m'); - return sdCardDesc.status; -} - -int SDHC_disk_read(BYTE *buff, DWORD sector, UINT count) -{ - DRESULT result = RES_OK; - LWord* pData = (LWord*)buff; -logg('A'); - // Check if this is ready - if(sdCardDesc.status != 0) return RES_NOTRDY; -logg('B'); - - // Check the valid Count of block - if(!count) return RES_PARERR; - - // Convert LBA to UCHAR address if needed - if(!sdCardDesc.highCapacity) sector *= 512; - -// delayMicroseconds(100); // this is workaround to avoid sdhc blocking on BREN -// m_sdhc_waitCmd13 = 1; -// uint32_t cnt = 1<<16; while ((--cnt) && sdhc_isBusy()) /* yield() */; if(!cnt) return RES_READERROR; -// m_sdhc_waitCmd13 = 0; -logg('C'); - - while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) /* yield() */; -logg('D'); - - SDHC_IRQSTAT = SDHC_IRQSTAT; // clear interrupt status register - - // - #if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA - SDHC_DSADDR = (LWord)pData; - SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; - #endif - - // use dma: disabling polling - uint32_t irqstat = SDHC_IRQSTATEN; - irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; - irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; - // enable status - irqstat |= SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ; - SDHC_IRQSTATEN = irqstat; - - uint32_t sigen = SDHC_IRQSIGEN; - sigen |= SDHC_IRQSIGEN_DMA_MASK ; - SDHC_IRQSIGEN = sigen; - - SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(SDHC_BLOCK_SIZE); - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL ; // read - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; // DMA - #endif - sdhc_enableDma(); -logg('E'); - - SDHC_CMDARG = sector; - SDHC_XFERTYP = count==1 ? SDHC_CMD17_XFERTYP: SDHC_CMD18_XFERTYP; - - #if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_SWPOLL - if(sdhc_waitCommandReady()) - result = sdhc_ReadBlock(pData,count,SDHC_BLOCK_SIZE); - else - result=RES_READERROR; - #elif SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA - result=RES_OK; - #endif -logg('F'); - // Auto CMD12 is enabled - if((result != RES_OK) && (count>1)) - result=sdhc_CMD12_StopTransferWaitForBusy(); - // wait for end of DMA -logg('G'); - sdhc_DMAWait(); - SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); -logg('H'); - - return result; -} - -int SDHC_disk_write(const BYTE *buff, DWORD sector, UINT count) -{ - DRESULT result = RES_OK; - LWord* pData = (LWord*)buff; - - // Check if this is ready - if(sdCardDesc.status != 0) return RES_NOTRDY; - - // Check the valid Count of block - if(!count) return RES_PARERR; - - // Convert LBA to UCHAR address if needed - if(!sdCardDesc.highCapacity) sector *= 512; - -// delayMicroseconds(100); // this is workaround to avoid sdhc blocking on BWEN - m_sdhc_waitCmd13 = 1; - uint32_t cnt = 1<<16; while ((--cnt) && sdhc_isBusy()) /* yield() */; if(!cnt) return RES_WRITEERROR; - m_sdhc_waitCmd13 = 0; - - while(SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB | SDHC_PRSSTAT_DLA)) /* yield() */; - - SDHC_IRQSTAT = 0xffff; // clear interrupt status register -#if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA - SDHC_DSADDR = (LWord)pData; -#endif - SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(SDHC_BLOCK_SIZE); - #if defined(__IMXRT1052__) - SDHC_MIX_CTRL &= ~ SDHC_MIX_CTRL_DTDSEL; // write - SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; //DMA - #endif - sdhc_enableDma(); - // if multi-block write - // pre-erase blocks - if(count>1) - { - sdhc_CMD(SDHC_CMD55_XFERTYP, 0); - sdhc_CMD(SDHC_ACMD23_XFERTYP, count); - - SDHC_CMDARG = sector; - SDHC_XFERTYP = SDHC_CMD25_XFERTYP; - } - else - { - SDHC_CMDARG = sector; - SDHC_XFERTYP = SDHC_CMD24_XFERTYP; - } - -// SDHC_CMDARG = sector; -// SDHC_XFERTYP = (count==1) ? SDHC_CMD24_XFERTYP: SDHC_CMD25_XFERTYP; - -#if SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_SWPOLL - if(sdhc_waitCommandReady()) - result = sdhc_WriteBlock(pData,count,SDHC_BLOCK_SIZE); - else - result=RES_WRITEERROR; -#elif SDHC_TRANSFERTYPE == SDHC_TRANSFERTYPE_DMA - result=RES_OK; -#endif - // Auto CMD12 is enabled for DMA - if((result != RES_OK) && (count>1)) - result=sdhc_CMD12_StopTransferWaitForBusy(); - -// wait for end of DMA - sdhc_DMAWait(); - - return result; -} - -int SDHC_ioctl(BYTE cmd, BYTE *buff) -{ - return RES_OK; -} -#endif - -#if defined(__MK20DX256__) // has no sdhc - int SDHC_disk_status(){ return RES_OK;} - int SDHC_disk_initialize(){ return RES_OK;} - int SDHC_disk_read(BYTE *buff, DWORD sector, UINT count){ return RES_OK;} - int SDHC_disk_write(const BYTE *buff, DWORD sector, UINT count){ return RES_OK;} - int SDHC_ioctl(BYTE cmd, BYTE *buff){ return RES_OK;} -#endif -#endif From e69160bd6030c2c64dc37856e050103c0cbc9c6a Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 11 Jul 2022 08:04:14 +0200 Subject: [PATCH 10/11] Updated for move of stepper enable initial stepper enable call to the core. --- grblHAL_Teensy4/src/driver.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/grblHAL_Teensy4/src/driver.c b/grblHAL_Teensy4/src/driver.c index 224ba82..0821e2d 100644 --- a/grblHAL_Teensy4/src/driver.c +++ b/grblHAL_Teensy4/src/driver.c @@ -1304,6 +1304,10 @@ bool spindleConfig (void) hal.spindle.set_state = spindleSetState; } +#if SPINDLE_SYNC_ENABLE + hal.spindle.cap.at_speed = hal.spindle.get_data == spindleGetData; +#endif + spindle_update_caps(hal.spindle.cap.variable); return true; @@ -1486,8 +1490,6 @@ static void settings_changed (settings_t *settings) { if(IOInitDone) { - stepperEnable(settings->steppers.deenergize); - #ifdef SQUARING_ENABLED hal.stepper.disable_motors((axes_signals_t){0}, SquaringMode_Both); #endif @@ -2241,7 +2243,7 @@ bool driver_init (void) options[strlen(options) - 1] = '\0'; hal.info = "iMXRT1062"; - hal.driver_version = "220703"; + hal.driver_version = "220710"; #ifdef BOARD_NAME hal.board = BOARD_NAME; #endif From 5cf91f3bb9baa4def8f3da7356dacbd383a6e4a3 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 11 Jul 2022 08:04:53 +0200 Subject: [PATCH 11/11] Updated submodules --- grblHAL_Teensy4/src/grbl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grblHAL_Teensy4/src/grbl b/grblHAL_Teensy4/src/grbl index e8530a4..651a2a9 160000 --- a/grblHAL_Teensy4/src/grbl +++ b/grblHAL_Teensy4/src/grbl @@ -1 +1 @@ -Subproject commit e8530a45ab5b386aa05956eb368e856ab5c520d9 +Subproject commit 651a2a903befdb6df1e77f263628b4ebfb63c931