mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
Diff: targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_sdhc.c
- Revision:
- 148:21d94c44109e
- Parent:
- 144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_sdhc.c Fri Sep 16 16:24:25 2016 +0100 +++ b/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_sdhc.c Fri Sep 30 18:07:01 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright (c) 2016, Freescale Semiconductor, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,6 +50,9 @@ #define SDHC_NEXT_CLKFS(x) ((x) <<= 1U) #define SDHC_PREV_CLKFS(x) ((x) >>= 1U) +/* Typedef for interrupt handler. */ +typedef void (*sdhc_isr_t)(SDHC_Type *base, sdhc_handle_t *handle); + /*! @brief ADMA table configuration */ typedef struct _sdhc_adma_table_config { @@ -230,6 +233,9 @@ /*! @brief SDHC clock array name */ static const clock_ip_name_t s_sdhcClock[] = SDHC_CLOCKS; +/* SDHC ISR for transactional APIs. */ +static sdhc_isr_t s_sdhcIsr; + /******************************************************************************* * Code ******************************************************************************/ @@ -288,10 +294,8 @@ static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data) { - assert(command); - uint32_t flags = 0U; - sdhc_transfer_config_t sdhcTransferConfig; + sdhc_transfer_config_t sdhcTransferConfig = {0}; sdhc_dma_mode_t dmaMode; /* Define the flag corresponding to each response type. */ @@ -315,7 +319,7 @@ flags |= (kSDHC_ResponseLength48Flag); break; case kSDHC_ResponseTypeR5: /* Response 5 */ - flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag); + flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag); break; case kSDHC_ResponseTypeR5b: /* Response 5 with busy */ flags |= (kSDHC_ResponseLength48BusyFlag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag); @@ -355,18 +359,9 @@ flags |= kSDHC_EnableAutoCommand12Flag; } } - if (data->blockCount > SDHC_MAX_BLOCK_COUNT) - { - sdhcTransferConfig.dataBlockSize = data->blockSize; - sdhcTransferConfig.dataBlockCount = SDHC_MAX_BLOCK_COUNT; - flags &= ~(uint32_t)kSDHC_EnableBlockCountFlag; - } - else - { - sdhcTransferConfig.dataBlockSize = data->blockSize; - sdhcTransferConfig.dataBlockCount = data->blockCount; - } + sdhcTransferConfig.dataBlockSize = data->blockSize; + sdhcTransferConfig.dataBlockCount = data->blockCount; } else { @@ -382,8 +377,6 @@ static void SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command) { - assert(command); - uint32_t i; if (command->responseType != kSDHC_ResponseTypeNone) @@ -412,13 +405,22 @@ static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords) { - assert(data); - uint32_t i; uint32_t totalWords; uint32_t wordsCanBeRead; /* The words can be read at this time. */ uint32_t readWatermark = ((base->WML & SDHC_WML_RDWML_MASK) >> SDHC_WML_RDWML_SHIFT); + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */ @@ -451,12 +453,21 @@ static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data) { - assert(data); - uint32_t totalWords; uint32_t transferredWords = 0U; status_t error = kStatus_Success; + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); while ((error == kStatus_Success) && (transferredWords < totalWords)) @@ -489,13 +500,22 @@ static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords) { - assert(data); - uint32_t i; uint32_t totalWords; uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */ uint32_t writeWatermark = ((base->WML & SDHC_WML_WRWML_MASK) >> SDHC_WML_WRWML_SHIFT); + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t)); /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/ @@ -528,12 +548,21 @@ static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data) { - assert(data); - uint32_t totalWords; uint32_t transferredWords = 0U; status_t error = kStatus_Success; + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (data->blockSize % sizeof(uint32_t) != 0U) + { + data->blockSize += + sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */ + } + totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t); while ((error == kStatus_Success) && (transferredWords < totalWords)) @@ -576,8 +605,6 @@ static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command) { - assert(command); - status_t error = kStatus_Success; /* Wait command complete or SDHC encounters error. */ @@ -602,8 +629,6 @@ static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data) { - assert(data); - status_t error = kStatus_Success; if (data->rxData) @@ -669,8 +694,6 @@ static void SDHC_TransferHandleCardDetect(sdhc_handle_t *handle, uint32_t interruptFlags) { - assert(interruptFlags & kSDHC_CardDetectFlag); - if (interruptFlags & kSDHC_CardInsertionFlag) { if (handle->callback.CardInserted) @@ -689,7 +712,7 @@ static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags) { - assert(interruptFlags & kSDHC_CommandFlag); + assert(handle->command); if ((interruptFlags & kSDHC_CommandErrorFlag) && (!(handle->data)) && (handle->callback.TransferComplete)) { @@ -709,7 +732,6 @@ static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags) { assert(handle->data); - assert(interruptFlags & kSDHC_DataFlag); if ((!(handle->data->enableIgnoreError)) && (interruptFlags & (kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag)) && (handle->callback.TransferComplete)) @@ -759,6 +781,8 @@ #if !defined FSL_SDHC_ENABLE_ADMA1 assert(config->dmaMode != kSDHC_DmaModeAdma1); #endif /* FSL_SDHC_ENABLE_ADMA1 */ + assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U)); + assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U)); uint32_t proctl; uint32_t wml; @@ -850,7 +874,8 @@ uint32_t SDHC_SetSdClock(SDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz) { - assert(busClock_Hz && (busClock_Hz < srcClock_Hz)); + assert(srcClock_Hz != 0U); + assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz)); uint32_t divisor; uint32_t prescaler; @@ -898,7 +923,7 @@ { base->SYSCTL |= SDHC_SYSCTL_INITA_MASK; /* Delay some time to wait card become active state. */ - while (!(base->SYSCTL & SDHC_SYSCTL_INITA_MASK)) + while (base->SYSCTL & SDHC_SYSCTL_INITA_MASK) { if (!timeout) { @@ -913,6 +938,8 @@ void SDHC_SetTransferConfig(SDHC_Type *base, const sdhc_transfer_config_t *config) { assert(config); + assert(config->dataBlockSize <= (SDHC_BLKATTR_BLKSIZE_MASK >> SDHC_BLKATTR_BLKSIZE_SHIFT)); + assert(config->dataBlockCount <= (SDHC_BLKATTR_BLKCNT_MASK >> SDHC_BLKATTR_BLKCNT_SHIFT)); base->BLKATTR = ((base->BLKATTR & ~(SDHC_BLKATTR_BLKSIZE_MASK | SDHC_BLKATTR_BLKCNT_MASK)) | (SDHC_BLKATTR_BLKSIZE(config->dataBlockSize) | SDHC_BLKATTR_BLKCNT(config->dataBlockCount))); @@ -975,12 +1002,13 @@ void SDHC_SetMmcBootConfig(SDHC_Type *base, const sdhc_boot_config_t *config) { assert(config); - - uint32_t mmcboot; + assert(config->ackTimeoutCount <= (SDHC_MMCBOOT_DTOCVACK_MASK >> SDHC_MMCBOOT_DTOCVACK_SHIFT)); + assert(config->blockCount <= (SDHC_MMCBOOT_BOOTBLKCNT_MASK >> SDHC_MMCBOOT_BOOTBLKCNT_SHIFT)); - mmcboot = base->MMCBOOT; - mmcboot |= (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) | - SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount)); + uint32_t mmcboot = 0U; + + mmcboot = (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) | + SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount)); if (config->enableBootAck) { mmcboot |= SDHC_MMCBOOT_BOOTACK_MASK; @@ -1016,6 +1044,9 @@ (!data) || (!dataBytes) #if !defined FSL_SDHC_ENABLE_ADMA1 || (dmaMode == kSDHC_DmaModeAdma1) +#else + /* Buffer address configured in ADMA1 descriptor must be 4KB aligned. */ + || ((dmaMode == kSDHC_DmaModeAdma1) && (((uint32_t)data % SDHC_ADMA1_LENGTH_ALIGN) != 0U)) #endif /* FSL_SDHC_ENABLE_ADMA1 */ ) { @@ -1029,6 +1060,17 @@ break; #if defined FSL_SDHC_ENABLE_ADMA1 case kSDHC_DmaModeAdma1: + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (dataBytes % sizeof(uint32_t) != 0U) + { + dataBytes += + sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */ + } + startAddress = data; /* Check if ADMA descriptor's number is enough. */ entries = ((dataBytes / SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); @@ -1054,7 +1096,7 @@ adma1EntryAddress[i + 1U] = ((uint32_t)(startAddress) << SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT); adma1EntryAddress[i + 1U] |= - (SDHC_ADMA1_DESCRIPTOR_TYPE_TRANSFER | SDHC_ADMA1_DESCRIPTOR_END_MASK); + (kSDHC_Adma1DescriptorTypeTransfer | kSDHC_Adma1DescriptorEndFlag); } else { @@ -1075,6 +1117,17 @@ break; #endif /* FSL_SDHC_ENABLE_ADMA1 */ case kSDHC_DmaModeAdma2: + /* + * Add non aligned access support ,user need make sure your buffer size is big + * enough to hold the data,in other words,user need make sure the buffer size + * is 4 byte aligned + */ + if (dataBytes % sizeof(uint32_t) != 0U) + { + dataBytes += + sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */ + } + startAddress = data; /* Check if ADMA descriptor's number is enough. */ entries = ((dataBytes / SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U); @@ -1125,15 +1178,14 @@ status_t SDHC_TransferBlocking(SDHC_Type *base, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer) { assert(transfer); - assert(transfer->command); /* Command must not be NULL, data can be NULL. */ status_t error = kStatus_Success; sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT); sdhc_command_t *command = transfer->command; sdhc_data_t *data = transfer->data; - /* DATA-PORT is 32-bit align, ADMA2 4 bytes align, ADMA1 is 4096 bytes align */ - if ((!command) || (data && (data->blockSize % 4U))) + /* make sure the cmd/block count is valid */ + if ((!command) || (data && (data->blockCount > SDHC_MAX_BLOCK_COUNT))) { error = kStatus_InvalidArgument; } @@ -1147,7 +1199,7 @@ { } - /* Update ADMA descriptor table if data isn't NULL. */ + /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ if (data && (kStatus_Success != SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords, (data->rxData ? data->rxData : data->txData), (data->blockCount * data->blockSize)))) @@ -1156,9 +1208,8 @@ } else { + /* Send command and receive data. */ SDHC_StartTransfer(base, command, data); - - /* Send command and receive data. */ if (kStatus_Success != SDHC_SendCommandBlocking(base, command)) { error = kStatus_SDHC_SendCommandFailed; @@ -1200,6 +1251,10 @@ /* Enable interrupt in NVIC. */ SDHC_SetTransferInterrupt(base, true); + + /* save IRQ handler */ + s_sdhcIsr = SDHC_TransferHandleIRQ; + EnableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]); } @@ -1213,8 +1268,8 @@ sdhc_command_t *command = transfer->command; sdhc_data_t *data = transfer->data; - /* DATA-PORT is 32-bit align, ADMA2 4 bytes align, ADMA1 is 4096 bytes align */ - if ((!(transfer->command)) || ((transfer->data) && (transfer->data->blockSize % 4U))) + /* make sure cmd/block count is valid */ + if ((!command) || (data && (data->blockCount > SDHC_MAX_BLOCK_COUNT))) { error = kStatus_InvalidArgument; } @@ -1228,7 +1283,7 @@ } else { - /* Update ADMA descriptor table and reset transferred words if data isn't NULL. */ + /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/ if (data && (kStatus_Success != SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords, (data->rxData ? data->rxData : data->txData), (data->blockCount * data->blockSize)))) @@ -1243,6 +1298,7 @@ handle->interruptFlags = 0U; /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */ handle->transferredWords = 0U; + SDHC_StartTransfer(base, command, data); } } @@ -1289,6 +1345,6 @@ { assert(s_sdhcHandle[0]); - SDHC_TransferHandleIRQ(SDHC, s_sdhcHandle[0]); + s_sdhcIsr(SDHC, s_sdhcHandle[0]); } #endif