diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/LCDTerm.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/LCDTerm.c index f572123e..141a1ee3 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/LCDTerm.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/LCDTerm.c @@ -190,7 +190,7 @@ void data_out(unsigned char i, SSP_DATA_SETUP_Type *xferConfig) //Data Output Se //CS = 0; //Chip Select = Active GPIO_ClearValue(3,(1<<12)); //A0 = 1 = Data - GPIO_SetValue(4,(1<<10)); + //GPIO_SetValue(4,(1<<10)); //delay(1); Tx_Buf[0] = i; @@ -206,7 +206,7 @@ void comm_out(unsigned char j, SSP_DATA_SETUP_Type *xferConfig) //Command Output { //unsigned int n; //CS = 0; //Chip Select = Active - GPIO_ClearValue(3,(1<<12)); + //GPIO_ClearValue(3,(1<<12)); //A0 = 0; GPIO_ClearValue(4,(1<<10)); //delay(1); diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/debug_frmwrk.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/debug_frmwrk.c index cdbf6598..c24ff87d 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/debug_frmwrk.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/debug_frmwrk.c @@ -280,6 +280,13 @@ void debug_frmwrk_init_clk(uint32_t Clock_Speed) */ scu_pinmux(0xC ,13 , MD_PDN, FUNC2); // PC.13 : UART1_TXD scu_pinmux(0xC ,14 , MD_PLN|MD_EZI|MD_ZI, FUNC2); // PC.14 : UART1_RXD +#elif (USED_UART_DEBUG_PORT==3) + /* + * Initialize UART3 pin connect + */ + scu_pinmux(0x2 ,3 , MD_PUP, FUNC2); // P2.3 : UART3_TXD + scu_pinmux(0x2 ,4 , MD_PLN|MD_EZI|MD_ZI, FUNC2); // P2.4 : UART3_RXD + #endif /* Initialize UART Configuration parameter structure to default state: diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_adc.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_adc.c index a7ce7e9b..8e41552a 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_adc.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_adc.c @@ -107,6 +107,10 @@ void ADC_DeInit(LPC_ADCn_Type *ADCx) { CHECK_PARAM(PARAM_ADCx(ADCx)); + if (ADCx->CR & ADC_CR_START_MASK) //need to stop START bits before DeInit + ADCx->CR &= ~ADC_CR_START_MASK; + // Clear SEL bits + ADCx->CR &= ~0xFF; // Clear PDN bit ADCx->CR &= ~ADC_CR_PDN; // Turn on power and clock @@ -251,6 +255,8 @@ void ADC_ChannelCmd (LPC_ADCn_Type *ADCx, uint8_t Channel, FunctionalState NewSt if (NewState == ENABLE) { ADCx->CR |= ADC_CR_CH_SEL(Channel); } else { + if (ADCx->CR & ADC_CR_START_MASK) //need to stop START bits before disable channel + ADCx->CR &= ~ADC_CR_START_MASK; ADCx->CR &= ~ADC_CR_CH_SEL(Channel); } } diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_cgu.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_cgu.c index 8ee04fd4..ba5306c2 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_cgu.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_cgu.c @@ -203,7 +203,6 @@ uint32_t CGU_Init(void){ CGU_EnableEntity(CGU_CLKSRC_PLL1, ENABLE); CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_M4); CGU_UpdateClock(); - SystemCoreClock = 6*12000000; return 0; } @@ -401,7 +400,7 @@ void CGU_UpdateClock(void){ CGU_ClockSourceFrequency[CGU_CLKSRC_32KHZ_OSC] = 0; /*PLL0*/ /* PLL1 */ - if(ISBITCLR(LPC_CGU->PLL1_CTRL,0) /* Enabled */ /* EA ANDLI: Original code tested bit 1 which is BYPASS, not PD */ + if(ISBITCLR(LPC_CGU->PLL1_CTRL,1) /* Enabled */ && (LPC_CGU->PLL1_STAT&1)){ /* Locked? */ ClkSrc = (LPC_CGU->PLL1_CTRL & CGU_CTRL_SRC_MASK)>>24; CGU_ClockSourceFrequency[CGU_CLKSRC_PLL1] = CGU_ClockSourceFrequency[ClkSrc] * diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_i2s.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_i2s.c index 5231d19c..a777c10e 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_i2s.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_i2s.c @@ -377,7 +377,7 @@ Status I2S_FreqConfig(LPC_I2Sn_Type *I2Sx, uint32_t Freq, uint8_t TRMode) { divider = ((uint64_t)(Freq *( bitrate+1) * 2)<<16) / i2sPclk; /* find N that make x/y <= 1 -> divider <= 2^16 */ - for(N=64;N>=0;N--){ + for(N=64;N>0;N--){ if((divider*N) < (1<<16)) break; } @@ -407,11 +407,11 @@ Status I2S_FreqConfig(LPC_I2Sn_Type *I2Sx, uint32_t Freq, uint8_t TRMode) { if(x_divide == 0) x_divide = 1; if (TRMode == I2S_TX_MODE)// Transmitter { - I2Sx->TXBITRATE = N; + I2Sx->TXBITRATE = N - 1; I2Sx->TXRATE = y_divide | (x_divide << 8); } else //Receiver { - I2Sx->RXBITRATE = N; + I2Sx->RXBITRATE = N - 1; I2Sx->RXRATE = y_divide | (x_divide << 8); } return SUCCESS; diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_lcd.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_lcd.c index 3bf3b5d9..5d2db52f 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_lcd.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_lcd.c @@ -109,11 +109,11 @@ void LCD_Init(LPC_LCD_Type *LCDx, LCD_CFG_Type *LCD_ConfigStruct){ break; case LCD_TFT: default: - regValue |= 1<<26 | (((LCD_ConfigStruct->screen_width-1) & 0x3FF) << 16); + regValue |= /* 1<<26 |*/ (((LCD_ConfigStruct->screen_width-1) & 0x3FF) << 16); } /* panel clock divisor */ - pcd = 0; // TODO: should be calculated from LCDDCLK + pcd = 6; // TODO: should be calculated from LCDDCLK pcd &= 0x3FF; regValue |= ((pcd>>5)<<27) | ((pcd)&0x1F); diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_qei.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_qei.c index 93c38745..2c2e05ff 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_qei.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_qei.c @@ -292,6 +292,7 @@ void QEI_SetTimerReload(uint8_t qeiId, QEI_RELOADCFG_Type *QEIReloadStruct) #if 1 // pclk = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M3CORE); pclk = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M4CORE); + pclk = (pclk /(1000000/QEIReloadStruct->ReloadValue)) - 1; pQei->LOAD = (uint32_t)pclk; diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_rtc.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_rtc.c index 234cb982..34273fa8 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_rtc.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_rtc.c @@ -209,7 +209,7 @@ void RTC_CntIncrIntConfig (LPC_RTC_Type *RTCx, uint32_t CntIncrIntType, \ { RTCx->CIIR |= tem; } - //while((RTCx->CIIR & tem)== 0); + while((RTCx->CIIR & tem)== 0); } else { @@ -217,7 +217,7 @@ void RTC_CntIncrIntConfig (LPC_RTC_Type *RTCx, uint32_t CntIncrIntType, \ { RTCx->CIIR &= (~tem) & RTC_CIIR_BITMASK; } - //while(RTCx->CIIR & tem); + while(RTCx->CIIR & tem); } } @@ -284,7 +284,7 @@ void RTC_AlarmIntConfig (LPC_RTC_Type *RTCx, uint32_t AlarmTimeType, \ { RTCx->AMR &= (~tem) & RTC_AMR_BITMASK; } - //while(RTCx->AMR & tem); + while(RTCx->AMR & tem); } else { @@ -292,7 +292,7 @@ void RTC_AlarmIntConfig (LPC_RTC_Type *RTCx, uint32_t AlarmTimeType, \ { RTCx->AMR |= (tem); } - //while((RTCx->AMR & tem)== 0); + while((RTCx->AMR & tem)== 0); } } @@ -699,7 +699,7 @@ void RTC_CalibConfig(LPC_RTC_Type *RTCx, uint32_t CalibValue, uint8_t CalibDir) CHECK_PARAM(PARAM_RTC_CALIB_DIR(CalibDir)); CHECK_PARAM(CalibValue < RTC_CALIBRATION_MAX); - RTCx->CALIBRATION = ((CalibValue - 1) & RTC_CALIBRATION_CALVAL_MASK) \ + RTCx->CALIBRATION = (CalibValue & RTC_CALIBRATION_CALVAL_MASK) \ | ((CalibDir == RTC_CALIB_DIR_BACKWARD) ? RTC_CALIBRATION_LIBDIR : 0); } diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_scu.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_scu.c index d583d7f8..fa5afd9e 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_scu.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_scu.c @@ -39,21 +39,60 @@ #include "lpc_types.h" #include "lpc43xx_scu.h" +/* Pin modes +* ========= +* The EPUN and EPD bits in the SFS registers allow the selection of weak on-chip +* pull-up or pull-down resistors with a typical value of 50 kOhm for each pin or the +* selection of the repeater mode. +* The possible on-chip resistor configurations are pull-up enabled, pull-down enabled, or no +* pull-up/pull-down. The default value is pull-up enabled. +* +* The repeater mode enables the pull-up resistor if the pin is at a logic HIGH and enables +* the pull-down resistor if the pin is at a logic LOW. This causes the pin to retain its last +* known state if it is configured as an input and is not driven externally. Repeater mode may +* typically be used to prevent a pin from floating (and potentially using significant power if it +* floats to an indeterminate state) if it is temporarily not driven. +* Repeater mode is enabled when both pull-up and pull-down are enabled. +* +* To be able to receive a digital signal, the input buffer must be enabled through bit EZI in +* the pin configuration registers. By default, the input buffer is disabled. +* For pads that support both a digital and an analog function, the input buffer must be +* disabled before enabling the analog function. +* +* All digital pins support a programmable glitch filter (bit ZIF), which can be switched on or +* off. By default, the glitch filter is on. The glitch filter should be disabled for +* clocking signals with frequencies higher than 30 MHz. +* +* Normal-drive and high-speed pins support a programmable slew rate (bit EHS) to select +* between lower noise and low speed or higher noise and high speed . The typical +* frequencies supported are 50 MHz/80 MHz for normal-drive pins and 75 MHz/180 MHz for +* high-speed pins. +*/ /*********************************************************************//** * @brief Configure pin function * @param[in] port Port number, should be: 0..15 - * @param[in] pin Pin number, should be: 0..31 + * @param[in] pin Pin number, should be: 0..31 * @param[in] mode Pin mode, should be: * - MD_PUP :Pull-up enabled * - MD_BUK :Plain input * - MD_PLN :Repeater mode * - MD_PDN :Pull-down enabled + * - MD_EHS :Slew rate + * - MD_EZI :Input buffer enable + * - MD_ZI :Glitch filter enabled + * - MD_EHD0 :High drive 8 mA + * - MD_EHD1 :High drive 14 mA + * - MD_EHD2 :High drive 20 mA * @param[in] func Function mode, should be: * - FUNC0 :Function 0 * - FUNC1 :Function 1 * - FUNC2 :Function 2 * - FUNC3 :Function 3 + * - FUNC4 :Function 4 + * - FUNC5 :Function 5 + * - FUNC6 :Function 6 + * - FUNC7 :Function 7 * @return None **********************************************************************/ void scu_pinmux(uint8_t port, uint8_t pin, uint8_t mode, uint8_t func) diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_sdif.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_sdif.c new file mode 100644 index 00000000..45d79a91 --- /dev/null +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_sdif.c @@ -0,0 +1,401 @@ +/********************************************************************** +* $Id$ lpc43xx_sdif.c 2012-Aug-15 +*//** +* @file lpc43xx_sdif.c +* @brief LPC43xx SD interface driver +* @version 1.0 +* @date 15. Aug. 2012 +* @author NXP MCU SW Application Team +* +* Copyright(C) 2011, NXP Semiconductor +* All rights reserved. +* +*********************************************************************** +* Software that is described herein is for illustrative purposes only +* which provides customers with programming information regarding the +* products. This software is supplied "AS IS" without any warranties. +* NXP Semiconductors assumes no responsibility or liability for the +* use of the software, conveys no license or title under any patent, +* copyright, or mask work right to the product. NXP Semiconductors +* reserves the right to make changes in the software without +* notification. NXP Semiconductors also make no representation or +* warranty that such application will be suitable for the specified +* use without further testing or modification. +* Permission to use, copy, modify, and distribute this software and its +* documentation is hereby granted, under NXP Semiconductors' +* relevant copyright in the software, without fee, provided that it +* is used in conjunction with NXP Semiconductors microcontrollers. This +* copyright, permission, and disclaimer notice must appear in all copies of +* this code. +**********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup SDIF + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "LPC43xx.h" /* LPC43xx definitions */ +#include "system_LPC43xx.h" +#include "lpc_sdmmc.h" +#include "lpc43xx_sdif.h" +#include "lpc43xx_cgu.h" + +/* If this source file built with example, the lpc43xx FW library configuration + * file in each example directory ("lpc43xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc43xx_libcfg.h" +#else +#include "lpc43xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _SDIF + +/* Local data structure for the SDIF driver */ +struct _sdif_device { + MCI_IRQ_CB_FUNC_T irq_cb; + LPC_SDMMC_DMA_Type mci_dma_dd[1 + (0x10000 / MCI_DMADES1_MAXTR)]; + uint32_t sdio_clk_rate; + uint32_t sdif_slot_clk_rate; + int32_t clock_enabled; +}; +static struct _sdif_device sdif_dev; + +/*********************************************************************//** +* @brief Enables the SDIO controller clock +* @param[in] None +* @return None +**********************************************************************/ +static void sdif_enable_clock(void) +{ + if (!sdif_dev.clock_enabled) + { + /* Enable SD MMC clock */ + CGU_ConfigPWR(CGU_PERIPHERAL_SDIO, ENABLE); + sdif_dev.clock_enabled = 1; + } +} + +/*********************************************************************//** +* @brief Disables the SDIO controller clock +* @param[in] None +* @return None +**********************************************************************/ +static void sdif_disable_clock(void) +{ + if (!sdif_dev.clock_enabled) + { + /* Disable SD MMC clock */ + CGU_ConfigPWR(CGU_PERIPHERAL_SDIO, (FunctionalState)FALSE); + sdif_dev.clock_enabled = 0; + } +} + +/* Public Functions ----------------------------------------------------------- */ +/** @defgroup SDIF_Public_Functions + * @ingroup SDIF + * @{ + */ + +/*********************************************************************//** +* @brief Setup DMA descriptors +* @param[in] addr Address of buffer (source or destination) +* @param[in] size size of buffer in bytes (64K max) +* @return None +**********************************************************************/ +void sdif_dma_setup(uint32_t addr, uint32_t size) +{ + int i = 0; + uint32_t ctrl, maxs; + + /* Reset DMA */ + LPC_SDMMC->CTRL |= MCI_CTRL_DMA_RESET | MCI_CTRL_FIFO_RESET; + while (LPC_SDMMC->CTRL & MCI_CTRL_DMA_RESET); + + /* Build a descriptor list using the chained DMA method */ + while (size > 0) + { + /* Limit size of the transfer to maximum buffer size */ + maxs = size; + if (maxs > MCI_DMADES1_MAXTR) + maxs = MCI_DMADES1_MAXTR; + size -= maxs; + + /* Set buffer size */ + sdif_dev.mci_dma_dd[i].des1 = MCI_DMADES1_BS1(maxs); + + /* Setup buffer address (chained) */ + sdif_dev.mci_dma_dd[i].des2 = addr + (i * MCI_DMADES1_MAXTR); + + /* Setup basic control */ + ctrl = MCI_DMADES0_OWN | MCI_DMADES0_CH; + if (i == 0) + ctrl |= MCI_DMADES0_FS; /* First DMA buffer */ + + /* No more data? Then this is the last descriptor */ + if (!size) + ctrl |= MCI_DMADES0_LD; + else + ctrl |= MCI_DMADES0_DIC; + + /* Another descriptor is needed */ + sdif_dev.mci_dma_dd[i].des3 = (uint32_t) &sdif_dev.mci_dma_dd[i + 1]; + sdif_dev.mci_dma_dd[i].des0 = ctrl; + + i++; + } + + /* Set DMA derscriptor base address */ + LPC_SDMMC->DBADDR = (uint32_t) &sdif_dev.mci_dma_dd[0]; +} + +/*********************************************************************//** +* @brief Function to send command to Card interface unit (CIU) +* @param[in] cmd Command with all flags set +* @param[in] arg Argument for the command +* @return TRUE on times-out, otherwise FALSE +**********************************************************************/ +int32_t sdif_send_cmd(uint32_t cmd, uint32_t arg) +{ + volatile int32_t tmo = 50; + volatile int delay; + + /* set command arg reg*/ + LPC_SDMMC->CMDARG = arg; + LPC_SDMMC->CMD = MCI_CMD_START | cmd; + + /* poll untill command is accepted by the CIU */ + while (--tmo && (LPC_SDMMC->CMD & MCI_CMD_START)) + { + if (tmo & 1) + delay = 50; + else + delay = 18000; + + while (--delay > 1); + } + + return (tmo < 1) ? 1 : 0; +} + +/*********************************************************************//** +* @brief Function to retrieve command response +* @param[in] pdev Pointer to card info structure +* @return None +**********************************************************************/ +void sdif_get_response(uint32_t *resp) +{ + /* on this chip response is not a fifo so read all 4 regs */ + resp[0] = LPC_SDMMC->RESP0; + resp[1] = LPC_SDMMC->RESP1; + resp[2] = LPC_SDMMC->RESP2; + resp[3] = LPC_SDMMC->RESP3; +} + +/*********************************************************************//** +* @brief Function to set speed of the clock going to card +* @param[in] speed Desired clock speed to the card +* @return None +**********************************************************************/ +void sdif_set_clock(uint32_t speed) +{ + /* compute SD/MMC clock dividers */ + uint32_t div; + + /* Exit if the clock is already set at the passed speed */ + if (sdif_dev.sdif_slot_clk_rate == speed) + return; + + div = ((sdif_dev.sdio_clk_rate / speed) + 2) >> 1; + sdif_dev.sdif_slot_clk_rate = speed; + + if ((div == LPC_SDMMC->CLKDIV) && LPC_SDMMC->CLKENA) + return; /* Closest speed is already set */ + + /* disable clock */ + LPC_SDMMC->CLKENA = 0; + + /* User divider 0 */ + LPC_SDMMC->CLKSRC = MCI_CLKSRC_CLKDIV0; + + /* inform CIU */ + sdif_send_cmd(MCI_CMD_UPD_CLK | MCI_CMD_PRV_DAT_WAIT, 0); + + /* set divider 0 to desired value */ + LPC_SDMMC->CLKDIV = MCI_CLOCK_DIVIDER(0, div); + + /* inform CIU */ + sdif_send_cmd(MCI_CMD_UPD_CLK | MCI_CMD_PRV_DAT_WAIT, 0); + + /* enable clock */ + LPC_SDMMC->CLKENA = MCI_CLKEN_ENABLE; + + /* inform CIU */ + sdif_send_cmd(MCI_CMD_UPD_CLK | MCI_CMD_PRV_DAT_WAIT, 0); +} + +/*********************************************************************//** +* @brief Detect if an SD card is inserted +* @param[in] None +* @return Returns 0 if a card is detected, otherwise 1 +**********************************************************************/ +int32_t sdif_card_ndetect(void) +{ + /* No card = high state in regsiter */ + if (LPC_SDMMC->CDETECT & 1) + return 0; + + return 1; +} + +/*********************************************************************//** +* @brief Detect if write protect is enabled +* @param[in] None +* @return Returns 1 if card is write protected, otherwise 0 +**********************************************************************/ +int32_t sdif_card_wp_on(void) +{ + if (LPC_SDMMC->WRTPRT & 1) + return 1; + + return 0; +} + +/*********************************************************************//** +* @brief Enable or disable slot power +* @param[in] enable !0 to enable, or 0 to disable +* @return None +**********************************************************************/ +void sdif_power_onoff(int32_t enable) +{ + if (enable) + LPC_SDMMC->PWREN = 1; + else + LPC_SDMMC->PWREN = 0; +} + +/*********************************************************************//** +* @brief Reset card in slot +* @param[in] reset Sets SD_RST to passed state +* @return None +**********************************************************************/ +void sdif_reset(int32_t reset) +{ + if (reset) + LPC_SDMMC->RST_N = 1; + else + LPC_SDMMC->RST_N = 0; +} + +/*********************************************************************//** +* @brief Set block size for transfer +* @param[in] bytes Lock size in bytes +* @return None +**********************************************************************/ +void sdif_set_blksize(uint32_t bytes) +{ + LPC_SDMMC->BLKSIZ = bytes; +} + +/*********************************************************************//** +* @brief Enter or exit low power mode (disables clocking) +* @param[in] lpmode !0 to enable low power mode, 0 = exit +* @return None +**********************************************************************/ +void sdif_set_lowpower_mode(int32_t lpmode) +{ + /* Once in low power mode, no SDIF functions should ever be + called, as it can hang the chip. Always exit low power mode + prior to resuming SDIF functions */ + if (lpmode) + sdif_disable_clock(); + else + sdif_enable_clock(); +} + +/*********************************************************************//** +* @brief Initializes the MCI card controller +* @param[in] waitfunc Pointer to wait function to be used during for poll command status +* @param[in] irq_callback Pointer to IRQ callback function +* @return None +**********************************************************************/ +void sdif_init(uint32_t sdio_clock, MCI_IRQ_CB_FUNC_T irq_callback) +{ + volatile uint32_t i; + + sdif_dev.sdio_clk_rate = sdio_clock; + sdif_dev.irq_cb = irq_callback; + + /* enable SD/MMC clock */ + sdif_enable_clock(); + + /* Software reset */ + LPC_SDMMC->BMOD = MCI_BMOD_SWR; + + /* reset all blocks */ + LPC_SDMMC->CTRL = MCI_CTRL_RESET | MCI_CTRL_FIFO_RESET | + MCI_CTRL_DMA_RESET; + while (LPC_SDMMC->CTRL & + (MCI_CTRL_RESET | MCI_CTRL_FIFO_RESET | MCI_CTRL_DMA_RESET)); + + /* Internal DMA setup for control register */ + LPC_SDMMC->CTRL = MCI_CTRL_USE_INT_DMAC | MCI_CTRL_INT_ENABLE; + LPC_SDMMC->INTMASK = 0; + + /* Clear the interrupts for the host controller */ + LPC_SDMMC->RINTSTS = 0xFFFFFFFF; + + /* Put in max timeout */ + LPC_SDMMC->TMOUT = 0xFFFFFFFF; + + /* FIFO threshold settings for DMA, DMA burst of 4, + FIFO watermark at 16 */ + LPC_SDMMC->FIFOTH = MCI_FIFOTH_DMA_MTS_4 | + MCI_FIFOTH_RX_WM((SD_FIFO_SZ / 2) - 1) | + MCI_FIFOTH_TX_WM(SD_FIFO_SZ / 2); + + /* Enable internal DMA, burst size of 4, fixed burst */ + LPC_SDMMC->BMOD = MCI_BMOD_DE | MCI_BMOD_PBL4 | MCI_BMOD_DSL(4); + + /* disable clock to CIU (needs latch) */ + LPC_SDMMC->CLKENA = 0; + LPC_SDMMC->CLKSRC = 0; +} + +/*********************************************************************//** +* @brief Close the MCI +* @param[in] None +* @return None +**********************************************************************/ +void sdif_deinit(void) +{ + /* clear mmc structure*/ + sdif_disable_clock(); +} + +/*********************************************************************//** +* @brief SDIO controller interrupt handler +* @param[in] None +* @return None +**********************************************************************/ +void SDIO_IRQHandler(void) +{ + /* All SD based register handling is done in the callback + function. The SDIO interrupt is not enabled as part of this + driver and needs to be enabled/disabled in the callbacks or + application as needed. This is to allow flexibility with IRQ + handling for applicaitons and RTOSes. */ + sdif_dev.irq_cb(LPC_SDMMC->RINTSTS); +} + +/** + * @} + */ + +#endif /* _SDIF */ + +/** + * @} + */ diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_sdmmc.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_sdmmc.c new file mode 100644 index 00000000..c24374b4 --- /dev/null +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_sdmmc.c @@ -0,0 +1,694 @@ +/********************************************************************** +* $Id$ lpc43xx_sdmmc.c 2012-Aug-15 +*//** +* @file lpc43xx_sdmmc.c +* @brief SD/MMC card access and data driver +* @version 1.0 +* @date 15. Aug. 2012 +* @author NXP MCU SW Application Team +* +* Copyright(C) 2011, NXP Semiconductor +* All rights reserved. +* +*********************************************************************** +* Software that is described herein is for illustrative purposes only +* which provides customers with programming information regarding the +* products. This software is supplied "AS IS" without any warranties. +* NXP Semiconductors assumes no responsibility or liability for the +* use of the software, conveys no license or title under any patent, +* copyright, or mask work right to the product. NXP Semiconductors +* reserves the right to make changes in the software without +* notification. NXP Semiconductors also make no representation or +* warranty that such application will be suitable for the specified +* use without further testing or modification. +* Permission to use, copy, modify, and distribute this software and its +* documentation is hereby granted, under NXP Semiconductors' +* relevant copyright in the software, without fee, provided that it +* is used in conjunction with NXP Semiconductors microcontrollers. This +* copyright, permission, and disclaimer notice must appear in all copies of +* this code. +**********************************************************************/ + +/* Example group ----------------------------------------------------------- */ +/** @addtogroup SDMMC + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "string.h" +#include "lpc_sdmmc.h" +#include "lpc43xx_sdif.h" +#include "lpc43xx_sdmmc.h" + +/* If this source file built with example, the lpc43xx FW library configuration + * file in each example directory ("lpc43xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc43xx_libcfg.h" +#else +#include "lpc43xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _SDMMC + +/* Global instance of the current card */ +static struct _mci_card_struct *g_card_info; + +/* Pointer to event setup functions */ +static MCI_EVSETUP_FUNC_T sdmmc_evsetup_cb; + +/* Pointer to wait functions */ +static MCI_WAIT_CB_FUNC_T sdmmc_wait_cb; + +/* Pointer to mS delay functin */ +static MCI_MSDELAY_FUNC_T sdmmc_msdelay_cb; + +/* Helper definition: all SD error conditions in the status word */ +#define SD_INT_ERROR (MCI_INT_RESP_ERR | MCI_INT_RCRC | MCI_INT_DCRC | \ + MCI_INT_RTO | MCI_INT_DTO | MCI_INT_HTO | MCI_INT_FRUN | MCI_INT_HLE | \ + MCI_INT_SBE | MCI_INT_EBE) + +/*********************************************************************//** +* @brief Helper function to get a bit field withing multi-word +* buffer. Used to get fields with-in CSD & EXT-CSD +* structures. +* @param[in] start Starting bit +* @param[in] end Ending bit +* @param[in] data Pointer to data patternf or bit extraction +* @return None +**********************************************************************/ +static uint32_t prv_get_bits(int32_t start, int32_t end, uint32_t* data) +{ + uint32_t v; + uint32_t i = end >> 5; + uint32_t j = start & 0x1f; + + if (i == (start >> 5)) + v = (data[i] >> j); + else + v = ((data[i] << (32 - j)) | (data[start >> 5] >> j)); + + return (v & ((1 << (end - start + 1)) - 1)); +} + +/*********************************************************************//** +* @brief Function to execute a command +* @param[in] cmd Command with all flags set +* @param[in] arg Argument for the command +* @param[in] wait_status Status bits to poll for command completion +* @return 0 on success, or error code (-1) +**********************************************************************/ +static int32_t sdmmc_execute_command(uint32_t cmd, uint32_t arg, + uint32_t wait_status) +{ + int32_t step = (cmd & CMD_BIT_APP) ? 2 : 1; + int32_t status = 0; + uint32_t cmd_reg = 0; + + if (!wait_status) + wait_status = (cmd & CMD_MASK_RESP) ? MCI_INT_CMD_DONE : MCI_INT_DATA_OVER; + + /* Clear the interrupts & FIFOs*/ + if (cmd & CMD_BIT_DATA) + { + /* reset all blocks */ + LPC_SDMMC->CTRL |= MCI_CTRL_FIFO_RESET; + + /* wait till resets clear */ + while (LPC_SDMMC->CTRL & MCI_CTRL_FIFO_RESET); + + /* Clear interrupt status */ + LPC_SDMMC->RINTSTS = 0xFFFFFFFF; + } + + /* also check error conditions */ + wait_status |= MCI_INT_EBE | MCI_INT_SBE | MCI_INT_HLE | + MCI_INT_RTO | MCI_INT_RCRC | MCI_INT_RESP_ERR; + if (wait_status & MCI_INT_DATA_OVER) + wait_status |= MCI_INT_FRUN | MCI_INT_HTO | MCI_INT_DTO | MCI_INT_DCRC; + + while (step) + { + sdif_set_clock((cmd & CMD_BIT_LS) ? SD_MMC_ENUM_CLOCK : g_card_info->speed); + + /* Clear the interrupts */ + LPC_SDMMC->RINTSTS = 0xFFFFFFFF; + sdmmc_evsetup_cb(wait_status); + + switch (step) + { + case 1: /* Execute command */ + cmd_reg = ((cmd & CMD_MASK_CMD) >> CMD_SHIFT_CMD) | + ((cmd & CMD_BIT_INIT) ? MCI_CMD_INIT : 0) | + ((cmd & CMD_BIT_DATA) ? (MCI_CMD_DAT_EXP | MCI_CMD_PRV_DAT_WAIT) : 0) | + (((cmd & CMD_MASK_RESP) == CMD_RESP_R2) ? MCI_CMD_RESP_LONG : 0) | + ((cmd & CMD_MASK_RESP) ? MCI_CMD_RESP_EXP : 0) | + ((cmd & CMD_BIT_WRITE) ? MCI_CMD_DAT_WR : 0) | + ((cmd & CMD_BIT_STREAM) ? MCI_CMD_STRM_MODE : 0) | + ((cmd & CMD_BIT_BUSY) ? MCI_CMD_STOP : 0) | + ((cmd & CMD_BIT_AUTO_STOP) ? MCI_CMD_SEND_STOP : 0) | + MCI_CMD_START; + + /* wait for previos data finsh for select/deselect commands */ + if (((cmd & CMD_MASK_CMD) >> CMD_SHIFT_CMD) == MMC_SELECT_CARD) + { + cmd_reg |= MCI_CMD_PRV_DAT_WAIT; + } + + /* wait for command to be accepted by CIU */ + if (sdif_send_cmd(cmd_reg, arg) == 0) + --step; + break; + + case 0: + return 0; + + case 2: /* APP prefix */ + cmd_reg = MMC_APP_CMD | MCI_CMD_RESP_EXP | + ((cmd & CMD_BIT_INIT) ? MCI_CMD_INIT : 0) | + MCI_CMD_START; + + if (sdif_send_cmd(cmd_reg, g_card_info->rca << 16) == 0) + --step; + break; + } + + /* wait for command response */ + status = sdmmc_wait_cb(wait_status); + + /* We return an error if there is a timeout, even if we've fetched + a response */ + if (status & SD_INT_ERROR) + return status; + + if (status & MCI_INT_CMD_DONE) + { + switch (cmd & CMD_MASK_RESP) + { + case 0: + break; + + case CMD_RESP_R1: + case CMD_RESP_R3: + sdif_get_response(&g_card_info->response[0]); + break; + + case CMD_RESP_R2: + sdif_get_response(&g_card_info->response[0]); + break; + } + } + } + + return 0; +} + +/*********************************************************************//** +* @brief Checks whether card is acquired properly or not +* @return !0 if card has been acquired, otherwise 0 +**********************************************************************/ +static int32_t prv_card_acquired(void) +{ + return (g_card_info->cid[0] != 0); +} + +/*********************************************************************//** +* @brief Function to process the CSD & EXT-CSD of the card +* @param[in] None +* @return None +**********************************************************************/ +static void prv_process_csd(void) +{ + int32_t status = 0; + int32_t c_size = 0; + int32_t c_size_mult = 0; + int32_t mult = 0; + + /* compute block length based on CSD response */ + g_card_info->block_len = 1 << prv_get_bits(80, 83, g_card_info->csd); + + if ((g_card_info->card_type & CARD_TYPE_HC) && + (g_card_info->card_type & CARD_TYPE_SD)) + { + /* See section 5.3.3 CSD Register (CSD Version 2.0) of SD2.0 spec + an explanation for the calculation of these values */ + c_size = prv_get_bits(48, 63, (uint32_t*)g_card_info->csd) + 1; + g_card_info->blocknr = c_size << 10; /* 512 byte blocks */ + } + else + { + /* See section 5.3 of the 4.1 revision of the MMC specs for + an explanation for the calculation of these values */ + c_size = prv_get_bits(62, 73, (uint32_t*)g_card_info->csd); + c_size_mult = prv_get_bits(47, 49, (uint32_t*)g_card_info->csd); + mult = 1 << (c_size_mult + 2); + g_card_info->blocknr = (c_size + 1) * mult; + + /* adjust blocknr to 512/block */ + if (g_card_info->block_len > MMC_SECTOR_SIZE) + g_card_info->blocknr = g_card_info->blocknr * + (g_card_info->block_len >> 9); + + /* get extended CSD for newer MMC cards CSD spec >= 4.0*/ + if (((g_card_info->card_type & CARD_TYPE_SD) == 0) && + (prv_get_bits(122, 125, (uint32_t*)g_card_info->csd) >= 4)) + { + /* put card in trans state */ + status = sdmmc_execute_command(CMD_SELECT_CARD, + g_card_info->rca << 16, 0); + + /* set block size and byte count */ + LPC_SDMMC->BLKSIZ = MMC_SECTOR_SIZE; + LPC_SDMMC->BYTCNT = MMC_SECTOR_SIZE; + + /* send EXT_CSD command */ + sdif_dma_setup((uint32_t) g_card_info->ext_csd, MMC_SECTOR_SIZE); + status = sdmmc_execute_command(CMD_SEND_EXT_CSD, 0, 0 | + MCI_INT_DATA_OVER); + if ((status & SD_INT_ERROR) == 0) + { + /* check EXT_CSD_VER is greater than 1.1 */ + if ((g_card_info->ext_csd[48] & 0xFF) > 1) + g_card_info->blocknr = g_card_info->ext_csd[53]; /* bytes 212:215 represent sec count */ + + /* switch to 52MHz clock if card type is set to 1 or else set to 26MHz */ + if ((g_card_info->ext_csd[49] & 0xFF) == 1) + { + /* for type 1 MMC cards high speed is 52MHz */ + g_card_info->speed = MMC_HIGH_BUS_MAX_CLOCK; + } + else + { + /* for type 0 MMC cards high speed is 26MHz */ + g_card_info->speed = MMC_LOW_BUS_MAX_CLOCK; + } + } + } + } + + g_card_info->device_size = g_card_info->blocknr << 9; /* blocknr * 512 */ +} + +/*********************************************************************//** +* @brief Puts current selected card in trans state +* @param[in] None +* @return 0 on success, or error code (-1) +**********************************************************************/ +static int32_t prv_set_trans_state(void) +{ + uint32_t status; + + /* get current state of the card */ + status = sdmmc_execute_command(CMD_SEND_STATUS, g_card_info->rca << 16, 0); + if (status & MCI_INT_RTO) + { + /* unable to get the card state. So return immediatly. */ + return -1; + } + + /* check card state in response */ + status = R1_CURRENT_STATE(g_card_info->response[0]); + switch (status) + { + case SDMMC_STBY_ST: + /* put card in 'Trans' state */ + status = sdmmc_execute_command(CMD_SELECT_CARD, g_card_info->rca << 16, 0); + if (status != 0) + { + /* unable to put the card in Trans state. So return immediatly. */ + return -1; + } + break; + + case SDMMC_TRAN_ST: + /*do nothing */ + break; + + default: + /* card shouldn't be in other states so return */ + return -1; + } + + return 0; +} + +/*********************************************************************//** +* @brief Sets card data width and block size +* @param[in] None +* @return 0 on success, or error code (-1) +**********************************************************************/ +static int32_t prv_set_card_params(void) +{ + uint32_t status; + +#if SDIO_BUS_WIDTH > 1 + if (g_card_info->card_type & CARD_TYPE_SD) + { + status = sdmmc_execute_command(CMD_SD_SET_WIDTH, 2, 0); + if (status != 0) + return -1; + + /* if positive response */ + LPC_SDMMC->CTYPE = MCI_CTYPE_4BIT; + } +#elif SDIO_BUS_WIDTH > 4 +#error 8-bit mode not supported yet! +#endif + + /* set block length */ + LPC_SDMMC->BLKSIZ = MMC_SECTOR_SIZE; + status = sdmmc_execute_command(CMD_SET_BLOCKLEN, MMC_SECTOR_SIZE, 0); + if (status != 0) + return -1; + + return 0; +} + +/* Public Functions ----------------------------------------------------------- */ +/** @defgroup SDMMC_Public_Functions + * @ingroup SDMMC + * @{ + */ + +/*********************************************************************//** +* @brief Function to enumerate the SD/MMC/SDHC/MMC+ cards +* @param[in] evsetup_cb Pointer to event setup function callback +* @param[in] waitfunc_cb Pointer to wait function callback +* @param[in] msdelay_func Pointer to function that delays +* @param[in] pcardinfo Pointer to pre-allocated card info structure +* @return 1 if a card is acquired, otherwise 0 +**********************************************************************/ +int32_t sdmmc_acquire(MCI_EVSETUP_FUNC_T evsetup_cb, + MCI_WAIT_CB_FUNC_T waitfunc_cb, MCI_MSDELAY_FUNC_T msdelay_func, + struct _mci_card_struct *pcardinfo) +{ + int32_t status; + int32_t tries = 0; + uint32_t ocr = OCR_VOLTAGE_RANGE_MSK; + uint32_t r; + int32_t state = 0; + uint32_t command = 0; + + g_card_info = pcardinfo; + + /* Make sure callbacks are valid */ + if ((waitfunc_cb == NULL) || (msdelay_func == NULL) || + (evsetup_cb == NULL)) + return 0; + + sdmmc_evsetup_cb = evsetup_cb; + sdmmc_wait_cb = waitfunc_cb; + sdmmc_msdelay_cb = msdelay_func; + + /* clear card struct */ + memset(g_card_info, 0, sizeof(*g_card_info)); + + /* clear card type */ + LPC_SDMMC->CTYPE = 0; + + /* set high speed for the card as 20MHz */ + g_card_info->speed = MMC_MAX_CLOCK; + + status = sdmmc_execute_command(CMD_IDLE, 0, MCI_INT_CMD_DONE); + + while (state < 100) + { + switch (state) + { + case 0: /* Setup for SD */ + /* check if it is SDHC card */ + status = sdmmc_execute_command( CMD_SD_SEND_IF_COND, SD_SEND_IF_ARG, 0); + if (!(status & MCI_INT_RTO)) + { + /* check response has same echo pattern */ + if ((g_card_info->response[0] & SD_SEND_IF_ECHO_MSK) == SD_SEND_IF_RESP) + ocr |= OCR_HC_CCS; + } + + ++state; + command = CMD_SD_OP_COND; + tries = INIT_OP_RETRIES; + + /* assume SD card */ + g_card_info->card_type |= CARD_TYPE_SD; + g_card_info->speed = SD_MAX_CLOCK; + break; + + case 10: /* Setup for MMC */ + /* start fresh for MMC crds */ + g_card_info->card_type &= ~CARD_TYPE_SD; + status = sdmmc_execute_command(CMD_IDLE, 0, MCI_INT_CMD_DONE); + command = CMD_MMC_OP_COND; + tries = INIT_OP_RETRIES; + ocr |= OCR_HC_CCS; + ++state; + + /* for MMC cards high speed is 20MHz */ + g_card_info->speed = MMC_MAX_CLOCK; + break; + + case 1: + case 11: + status = sdmmc_execute_command(command, 0, 0); + if (status & MCI_INT_RTO) + state += 9; /* Mode unavailable */ + else + ++state; + break; + + case 2: /* Initial OCR check */ + case 12: + ocr = g_card_info->response[0] | (ocr & OCR_HC_CCS); + if (ocr & OCR_ALL_READY) + ++state; + else + state += 2; + break; + + case 3: /* Initial wait for OCR clear */ + case 13: + while ((ocr & OCR_ALL_READY) && --tries > 0) + { + sdmmc_msdelay_cb(MS_ACQUIRE_DELAY); + status = sdmmc_execute_command(command, 0, 0); + ocr = g_card_info->response[0] | (ocr & OCR_HC_CCS); + } + if (ocr & OCR_ALL_READY) + state += 7; + else + ++state; + break; + + case 14: + /* for MMC cards set high capacity bit */ + ocr |= OCR_HC_CCS; + case 4: /* Assign OCR */ + tries = SET_OP_RETRIES; + ocr &= OCR_VOLTAGE_RANGE_MSK | OCR_HC_CCS; /* Mask for the bits we care about */ + do + { + sdmmc_msdelay_cb(MS_ACQUIRE_DELAY); + status = sdmmc_execute_command(command, ocr, 0); + r = g_card_info->response[0]; + } while (!(r & OCR_ALL_READY) && --tries > 0); + + if (r & OCR_ALL_READY) + { + /* is it high capacity card */ + g_card_info->card_type |= (r & OCR_HC_CCS); + ++state; + } + else + state += 6; + break; + + case 5: /* CID polling */ + case 15: + status = sdmmc_execute_command(CMD_ALL_SEND_CID, 0, 0); + memcpy(&g_card_info->cid, &g_card_info->response[0], 16); + ++state; + break; + + case 6: /* RCA send, for SD get RCA */ + status = sdmmc_execute_command(CMD_SD_SEND_RCA, 0, 0); + g_card_info->rca = (g_card_info->response[0]) >> 16; + ++state; + break; + + case 16: /* RCA assignment for MMC set to 1 */ + g_card_info->rca = 1; + status = sdmmc_execute_command(CMD_MMC_SET_RCA, g_card_info->rca << 16, 0); + ++state; + break; + + case 7: + case 17: + status = sdmmc_execute_command(CMD_SEND_CSD, g_card_info->rca << 16, 0); + memcpy(&g_card_info->csd, &g_card_info->response[0], 16); + state = 100; + break; + + default: + state += 100; /* break from while loop */ + break; + } + } + + /* Compute card size, block size and no. of blocks + based on CSD response recived. */ + if (prv_card_acquired()) { + prv_process_csd(); + + /* Setup card data width and block size (once) */ + if (prv_set_trans_state() != 0) + return 0; + if (prv_set_card_params() != 0) + return 0; + } + + return prv_card_acquired(); +} + +/*********************************************************************//** +* @brief Get card's current state (idle, transfer, program, etc.) +* @param[in] None +* @return Current transfer state (0 - +**********************************************************************/ +int32_t sdmmc_get_state(void) +{ + uint32_t status; + + /* get current state of the card */ + status = sdmmc_execute_command(CMD_SEND_STATUS, g_card_info->rca << 16, 0); + if (status & MCI_INT_RTO) + return -1; + + /* check card state in response */ + return (int32_t) R1_CURRENT_STATE(g_card_info->response[0]); +} + +/*********************************************************************//** +* @brief Get the device size of SD/MMC card +* @param[in] None +* @return Device size +**********************************************************************/ +int32_t sdmmc_get_device_size(void) +{ + return g_card_info->device_size; +} + +/*********************************************************************//** +* @brief Performs the read of data from the SD/MMC card +* @param[in] buffer Pointer to data buffer to copy to +* @param[in] start_block Start block number +* @param[in] end_block End block number +* @return Bytes read, or 0 on error +**********************************************************************/ +int32_t sdmmc_read_blocks(void* buffer, int32_t start_block, + int32_t end_block) +{ + int32_t cbRead = (end_block - start_block + 1) * MMC_SECTOR_SIZE; + int32_t status = 0; + int32_t index; + + /* if card is not acquired return immediately */ + if ((end_block < start_block) || (start_block < 0) || + (end_block > g_card_info->blocknr)) + return 0; + + /* put card in trans state */ + if (prv_set_trans_state() != 0) + return 0; + + /* set number of bytes to read */ + LPC_SDMMC->BYTCNT = cbRead; + + /* if high capacity card use block indexing */ + if (g_card_info->card_type & CARD_TYPE_HC) + index = start_block; + else/*fix at 512 bytes*/ + index = start_block << 9;//\* g_card_info->block_len; + + sdif_dma_setup((uint32_t) buffer, cbRead); + + /* Select single or multiple read based on number of blocks */ + if (end_block == start_block) + status = sdmmc_execute_command(CMD_READ_SINGLE, + index, 0 | MCI_INT_DATA_OVER); + else + status = sdmmc_execute_command(CMD_READ_MULTIPLE, + index, 0 | MCI_INT_DATA_OVER); + + if (status != 0) + cbRead = 0; + /*Wait for card program to finish*/ + while (sdmmc_get_state() != SDMMC_TRAN_ST); + + return cbRead; +} + +/*********************************************************************//** +* @brief Performs write of data to the SD/MMC card +* @param[in] buffer Pointer to data buffer to copy to +* @param[in] start_block Start block number +* @param[in] end_block End block number +* @return Number of bytes actually written, or 0 on error +**********************************************************************/ +int32_t sdmmc_write_blocks(void* buffer, + int32_t start_block, + int32_t end_block) +{ + int32_t cbWrote = (end_block - start_block + 1) * MMC_SECTOR_SIZE; + int32_t status; + int32_t index; + + /* if card is not acquired return immediately */ + if ((end_block < start_block) || (start_block < 0) || + (end_block > g_card_info->blocknr)) + return 0; + + /*Wait for card program to finish*/ + while (sdmmc_get_state() != SDMMC_TRAN_ST); + + /* put card in trans state */ + if (prv_set_trans_state() != 0) + return 0; + + /* set number of bytes to write */ + LPC_SDMMC->BYTCNT = cbWrote; + + /* if high capacity card use block indexing */ + if (g_card_info->card_type & CARD_TYPE_HC) + index = start_block; + else/*fix at 512 bytes*/ + index = start_block << 9;//* g_card_info->block_len; + + sdif_dma_setup((uint32_t) buffer, cbWrote); + + /*Wait for card program to finish*/ + while (sdmmc_get_state() != SDMMC_TRAN_ST); + + /* Select single or multiple write based on number of blocks */ + if (end_block == start_block) + status = sdmmc_execute_command(CMD_WRITE_SINGLE, + index, 0 | MCI_INT_DATA_OVER); + else + status = sdmmc_execute_command(CMD_WRITE_MULTIPLE, index, + 0 | MCI_INT_DATA_OVER); + + if (status != 0) + cbWrote = 0; + + return cbWrote; +} + +/** + * @} + */ + +#endif /* _SDMMC */ + +/** + * @} + */ diff --git a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_ssp.c b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_ssp.c index 19ddee58..4170d606 100644 --- a/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_ssp.c +++ b/demos/bsp/lpc43xx/CMSIS_LPC43xx_DriverLib/src/lpc43xx_ssp.c @@ -341,7 +341,7 @@ int32_t SSP_ReadWrite (LPC_SSPn_Type *SSPx, SSP_DATA_SETUP_Type *dataCfg, \ // Clear status SSPx->ICR = SSP_ICR_BITMASK; - if(SSP_GetDataSize(SSPx)>8) + if(SSP_GetDataSize(SSPx) > SSP_DATABIT_8) dataword = 1; else dataword = 0;