mbed-os/targets/TARGET_Cypress/TARGET_PSOC6/common/udb-sdio-whd/SDIO_HOST.c

1514 lines
53 KiB
C

/***************************************************************************//**
* \file SDIO_HOST.c
*
* \brief
* This file provides the source code to the API for the UDB based SDIO driver.
*
********************************************************************************
* \copyright
* Copyright 2016-2020 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
#include "SDIO_HOST.h"
#include "cy_utils.h"
#if defined(CYHAL_UDB_SDIO)
#if defined(__cplusplus)
extern "C" {
#endif
#ifdef CY_RTOS_AWARE
#include "cyabs_rtos.h"
#define NEVER_TIMEOUT ( (uint32_t)0xffffffffUL )
static cy_semaphore_t sdio_transfer_finished_semaphore;
static bool sema_initialized = false;
#endif
/* Backup struct used to store and restore non retention UDB registers */
typedef struct
{
uint32_t CY_SDIO_UDB_WRKMULT_CTL_0;
uint32_t CY_SDIO_UDB_WRKMULT_CTL_1;
uint32_t CY_SDIO_UDB_WRKMULT_CTL_2;
uint32_t CY_SDIO_UDB_WRKMULT_CTL_3;
} stc_sdio_backup_regs_t;
/*Globals Needed for DMA */
/*DMA channel structures*/
cy_stc_dma_channel_config_t respChannelConfig;
cy_stc_dma_channel_config_t cmdChannelConfig;
cy_stc_dma_channel_config_t writeChannelConfig;
cy_stc_dma_channel_config_t readChannelConfig;
/*DMA Descriptor structures*/
cy_stc_dma_descriptor_t respDesr;
cy_stc_dma_descriptor_t cmdDesr;
cy_stc_dma_descriptor_t readDesr0;
cy_stc_dma_descriptor_t readDesr1;
cy_stc_dma_descriptor_t writeDesr0;
cy_stc_dma_descriptor_t writeDesr1;
/*Global structure used for data keeping*/
stc_sdio_gInternalData_t gstcInternalData;
/*Global CRC table*/
static uint8_t crcTable[256];
/*Global values used for DMA interrupt*/
static uint32_t yCountRemainder;
static uint32_t yCounts;
/* Global value for card interrupt */
static uint8_t pfnCardInt_count = 0;
/*Global structure to store UDB registers */
static stc_sdio_backup_regs_t regs;
static uint32_t udb_initialized = 0;
cy_stc_syspm_callback_params_t sdio_pm_callback_params;
cy_stc_syspm_callback_t sdio_pm_callback_handler;
/* Deep Sleep Mode API Support */
static void SDIO_SaveConfig(void);
static void SDIO_RestoreConfig(void);
/*******************************************************************************
* Function Name: SDIO_DeepSleepCallback
****************************************************************************//**
*
* Callback executed during Deep Sleep entry/exit
*
* \param params
* Pointer to structure that holds callback parameters for this driver.
*
* \param mode
* The state transition mode that is currently happening.
*
* \note
* Saves/Restores SDIO UDB registers
*
* \return
* CY_SYSPM_SUCCESS if the transition was successful, otherwise CY_SYSPM_FAIL
*
*******************************************************************************/
cy_en_syspm_status_t SDIO_DeepSleepCallback(cy_stc_syspm_callback_params_t *params, cy_en_syspm_callback_mode_t mode)
{
CY_UNUSED_PARAMETER(params);
cy_en_syspm_status_t status = CY_SYSPM_FAIL;
switch (mode)
{
case CY_SYSPM_CHECK_READY:
case CY_SYSPM_CHECK_FAIL:
status = CY_SYSPM_SUCCESS;
break;
case CY_SYSPM_BEFORE_TRANSITION:
SDIO_SaveConfig();
status = CY_SYSPM_SUCCESS;
break;
case CY_SYSPM_AFTER_TRANSITION:
SDIO_RestoreConfig();
status = CY_SYSPM_SUCCESS;
break;
default:
break;
}
return status;
}
/*******************************************************************************
* Function Name: SDIO_Init
****************************************************************************//**
*
* Initializes the SDIO hardware
*
* \param pfuCb
* Pointer to structure that holds pointers to callback function
* see \ref stc_sdio_irq_cb_t.
*
* \note
* Sets SD Clock Frequency to 400 kHz
*******************************************************************************/
void SDIO_Init(stc_sdio_irq_cb_t* pfuCb)
{
if ( !udb_initialized )
{
udb_initialized = 1;
SDIO_Host_Config_TriggerMuxes();
SDIO_Host_Config_UDBs();
}
/*Set Number of Blocks to 1 initially, this will be updated later*/
SDIO_SetNumBlocks(1);
/*Enable SDIO ISR*/
NVIC_EnableIRQ((IRQn_Type) SDIO_HOST_sdio_int__INTC_NUMBER);
/*Enable the Status Reg to generate an interrupt*/
SDIO_STATUS_AUX_CTL |= (0x10);
/*Set the priority of DW0, DW1, M4 and M0. DW1 should have highest*/
/*First clear priority of all*/
(* (reg32 *)CYREG_PROT_SMPU_MS0_CTL) &= ~0x0300;
(* (reg32 *)CYREG_PROT_SMPU_MS2_CTL) &= ~0x0300;
(* (reg32 *)CYREG_PROT_SMPU_MS3_CTL) &= ~0x0300;
(* (reg32 *)CYREG_PROT_SMPU_MS14_CTL) &= ~0x0300;
/*Next set priority DW1 = 0, DW0 = 1, M4 = 2, M0 =3*/
(* (reg32 *)CYREG_PROT_SMPU_MS2_CTL) |= 0x0100;
(* (reg32 *)CYREG_PROT_SMPU_MS0_CTL) |= 0x0200;
(* (reg32 *)CYREG_PROT_SMPU_MS14_CTL) |= 0x0200;
/*Setup callback for card interrupt*/
gstcInternalData.pstcCallBacks.pfnCardIntCb = pfuCb->pfnCardIntCb;
/*Setup the DMA channels*/
SDIO_SetupDMA();
/*Initialize CRC*/
SDIO_Crc7Init();
/*Enable all the bit counters*/
SDIO_CMD_BIT_CNT_CONTROL_REG |= SDIO_ENABLE_CNT;
SDIO_WRITE_CRC_CNT_CONTROL_REG |= SDIO_ENABLE_CNT;
SDIO_CRC_BIT_CNT_CONTROL_REG |= SDIO_ENABLE_CNT;
SDIO_BYTE_CNT_CONTROL_REG |= SDIO_ENABLE_CNT;
/*Set block byte count to 64, this will be changed later */
SDIO_SetBlockSize(64);
/*Set the read and write FIFOs to use the half full status*/
(*(reg32 *) SDIO_HOST_bSDIO_Write_DP__DP_AUX_CTL_REG) |= 0x0c;
(*(reg32 *) SDIO_HOST_bSDIO_Read_DP__DP_AUX_CTL_REG) |= 0x0c;
/*Set clock to 400k, and enable it*/
SDIO_SetSdClkFrequency(400000);
SDIO_EnableIntClock();
SDIO_EnableSdClk();
}
/*******************************************************************************
* Function Name: SDIO_SendCommand
****************************************************************************//**
*
* Send an SDIO command, don't wait for it to finish.
*
* \param pstcCmdConfig
* Command configuration structure. See \ref stc_sdio_cmd_config_t.
*
*******************************************************************************/
void SDIO_SendCommand(stc_sdio_cmd_config_t *pstcCmdConfig)
{
/*buffer to hold command data*/
static uint8_t u8cmdBuf[6];
/*Populate buffer*/
/*Element 0 is the Most Significant Byte*/
u8cmdBuf[0] = SDIO_HOST_DIR | pstcCmdConfig->u8CmdIndex;
u8cmdBuf[1] = (uint8_t)((pstcCmdConfig->u32Argument & 0xff000000)>>24);
u8cmdBuf[2] = (uint8_t)((pstcCmdConfig->u32Argument & 0x00ff0000)>>16);
u8cmdBuf[3] = (uint8_t)((pstcCmdConfig->u32Argument & 0x0000ff00)>>8);
u8cmdBuf[4] = (uint8_t)((pstcCmdConfig->u32Argument & 0x000000ff));
/*calculate the CRC of above data*/
u8cmdBuf[5] = SDIO_CalculateCrc7(u8cmdBuf, 5);
/*Shift it up by 1 as the CRC takes the upper 7 bits of the last byte of the cmd*/
u8cmdBuf[5] = u8cmdBuf[5] << 1;
/*Add on the end bit*/
u8cmdBuf[5] = u8cmdBuf[5] | SDIO_CMD_END_BIT;
/*Load the first byte into A0*/
SDIO_CMD_COMMAND_A0_REG = u8cmdBuf[0];
/*If a response is expected setup DMA to receive the response*/
if (pstcCmdConfig->bResponseRequired == true)
{
/*Clear the flag in hardware that says skip response*/
SDIO_CONTROL_REG &= ~SDIO_CTRL_SKIP_RESPONSE;
/*Set the destination address*/
respDesr.dst = (uint32_t)(pstcCmdConfig->pu8ResponseBuf);
/*Initialize the channel with the descriptor*/
Cy_DMA_Channel_SetDescriptor(SDIO_HOST_Resp_DMA_HW, SDIO_HOST_Resp_DMA_DW_CHANNEL, &respDesr);
/*Enable the channel*/
Cy_DMA_Channel_Enable(SDIO_HOST_Resp_DMA_HW, SDIO_HOST_Resp_DMA_DW_CHANNEL);
}
else
{
/*Set the skip flag*/
SDIO_CONTROL_REG |= SDIO_CTRL_SKIP_RESPONSE;
}
/*Setup the Command DMA*/
/*Set the source address*/
cmdDesr.src = (uint32_t)(&u8cmdBuf[1]);
/*Initialize the channel with the descriptor*/
Cy_DMA_Channel_SetDescriptor(SDIO_HOST_CMD_DMA_HW, SDIO_HOST_CMD_DMA_DW_CHANNEL , &cmdDesr);
/*Enable the channel*/
Cy_DMA_Channel_Enable(SDIO_HOST_CMD_DMA_HW, SDIO_HOST_CMD_DMA_DW_CHANNEL );
}
/*******************************************************************************
* Function Name: SDIO_GetResponse
****************************************************************************//**
*
* Takes a 6 byte response buffer, and extracts the 32 bit response, also checks
* for index errors, CRC errors, and end bit errors.
*
* \param bCmdIndexCheck
* If True check for index errors
*
* \param bCmdCrcCheck
* If True check for CRC errors
*
* \param u8cmdIdx
* Command index, used for checking the index error
*
* \param pu32Response
* location to store 32 bit response
*
* \param pu8ResponseBuf
* buffer that holds the 6 bytes of response data
*
* \return
* \ref en_sdio_result_t
*
*******************************************************************************/
en_sdio_result_t SDIO_GetResponse(uint8_t bCmdIndexCheck, uint8_t bCmdCrcCheck, uint8_t u8cmdIdx, uint32_t* pu32Response, uint8_t *pu8ResponseBuf)
{
/*Function return*/
en_sdio_result_t enRet = Error;
/*variable to hold temporary CRC*/
uint8_t u8TmpCrc;
/*temporary response*/
uint32_t u32TmpResponse;
/*Zero out the pu32Response*/
*pu32Response = 0;
/*Check if the CRC needs to be checked*/
if (bCmdCrcCheck)
{
/*Calculate the CRC*/
u8TmpCrc = SDIO_CalculateCrc7(pu8ResponseBuf, 5);
/*Shift calculated CRC up by one bit to match bit position of CRC*/
u8TmpCrc = u8TmpCrc << 1;
/*Compare calculated CRC with received CRC*/
if ((u8TmpCrc & 0xfe) != (pu8ResponseBuf[5] & 0xfe))
{
enRet |= CommandCrcError;
}
}
/*Check if the index needs to be checked*/
if (bCmdIndexCheck)
{
/*The index resides in the lower 6 bits of the 1st byte of the response*/
if ((u8cmdIdx != (pu8ResponseBuf[0] & 0x3f)))
{
enRet |= CommandIdxError;
}
}
/*Check the end bit*/
if (!(pu8ResponseBuf[5] & 0x01))
{
enRet |= CommandEndError;
}
if (enRet == Error)
{
/*If we get here then there were no errors with the command populate the response*/
u32TmpResponse = pu8ResponseBuf[1];
u32TmpResponse = u32TmpResponse << 8;
u32TmpResponse |= pu8ResponseBuf[2];
u32TmpResponse = u32TmpResponse << 8;
u32TmpResponse |= pu8ResponseBuf[3];
u32TmpResponse = u32TmpResponse << 8;
u32TmpResponse |= pu8ResponseBuf[4];
*pu32Response = u32TmpResponse;
enRet = Ok;
}
return enRet;
}
/*******************************************************************************
* Function Name: SDIO_InitDataTransfer
****************************************************************************//**
*
* Configure the data channel for a data transfer. For a write this doesn't start
* the write, that must be done separately after the response is received.
*
* \param pstcDataConfig
* Data configuration structure. See \ref stc_sdio_data_config_t
*
*
*******************************************************************************/
void SDIO_InitDataTransfer(stc_sdio_data_config_t *pstcDataConfig)
{
/*hold size of entire transfer*/
uint32_t dataSize;
/*calculate how many bytes are going to be sent*/
dataSize = pstcDataConfig->u16BlockSize * pstcDataConfig->u16BlockCount;
/*Set the block size and number of blocks*/
SDIO_SetBlockSize(pstcDataConfig->u16BlockSize);
SDIO_SetNumBlocks((pstcDataConfig->u16BlockCount) - 1);
/*If we are reading data setup the DMA to receive read data*/
if (pstcDataConfig->bRead == true)
{
/*First disable the write channel*/
Cy_DMA_Channel_Disable(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL );
/*Clear any pending interrupts in the DMA*/
Cy_DMA_Channel_ClearInterrupt(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL);
NVIC_ClearPendingIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
/*setup the destination addresses*/
readDesr0.dst = (uint32_t)(pstcDataConfig->pu8Data);
readDesr1.dst = (uint32_t)((pstcDataConfig->pu8Data) + 1024);
/*Setup the X control to transfer two 16 bit elements per transfer for a total of 4 bytes
Remember X increment is in terms of data element size which is 16, thus why it is 1*/
readDesr0.xCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 1) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 1);
readDesr1.xCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 1) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 1);
/*The X Loop will always transfer 4 bytes. The FIFO will only trigger the
DMA when it has 4 bytes to send (2 in each F0 and F1). There is a possibility
that there could be 3,2,or 1 bytes still in the FIFOs. To solve this the DMA
will be SW triggered when hardware indicates all bytes have been received.
This leads to an extra 1, 2 or 3 bytes being received. So the RX buffer needs to
be at least 3 bytes bigger than the data size.
Since the X loop is setup to 4, the maximum number of Y loop is 256 so one
descriptor can transfer 1024 bytes. Two descriptors can transfer 2048 bytes.
Since we don't know the maximum number of bytes to read only two descriptors will
be used. If more than 2048 bytes need to be read then and interrupt will be enabled
The descriptor that is not currently running will be updated in the ISR to receive
more data.
So there are three conditions to check:
1) Are we sending less than or equal to 1024 bytes if so use one descriptor
2) Are we sending greater than 1024, but less than or equal to 2048, use two descriptors
3) Greater than 2048, use two descriptors and the ISR
*/
if (dataSize <= 1024)
{
/*Setup one descriptor*/
/*Y Increment is 2 because the X is transfer 2 data elements (which are 16 bits)*/
readDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (dataSize - 1) / 4) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
/*Setup descriptor 0 to point to nothing and disable*/
readDesr0.nextPtr = 0;
readDesr0.ctl |= 0x01000000;
/*Disable Interrupt*/
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
else if (dataSize <=2048)
{
/*setup the first descriptor for 1024, then setup 2nd descriptor for remainder*/
readDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 255) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
readDesr1.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (dataSize - 1025) / 4) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
/*Setup descriptor 0 to point to descriptor 1*/
readDesr0.nextPtr = (uint32_t)(&readDesr1);
/*Setup descriptor 1 to point to nothing and disable */
readDesr1.nextPtr = 0;
/*Don't disable after first descriptor*/
readDesr0.ctl &= ~0x01000000;
/*Disable after second descriptor*/
readDesr1.ctl |= 0x01000000;
/*Disable Interrupt*/
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
else /*dataSize must be greater than 2048*/
{
/*These are for the ISR, Need to figure out how many "descriptors"
need to run, and the yCount for last descriptor.
Example: dataSize = 2080
yCounts = 2, yCountRemainder = 7 (send 8 more set of 4)*/
yCounts = (dataSize / 1024);
/*the Ycount register is a +1 register meaning 0 = 1. I However, need to know when there is
no remainder so I increase the value to make sure there is a remainder and decrement in the ISR*/
yCountRemainder = (((dataSize - (yCounts * 1024)) + 3 ) / 4);
/*Setup the Y Ctrl for both descriptors*/
readDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 255) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
readDesr1.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 255) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
/*Setup descriptor 0 to point to descriptor 1*/
readDesr0.nextPtr = (uint32_t)(&readDesr1);
/*Setup descriptor 1 to point to descriptor 0*/
readDesr1.nextPtr = (uint32_t)(&readDesr0);
/*Don't disable the channel on completion of descriptor*/
readDesr0.ctl &= ~0x01000000;
readDesr1.ctl &= ~0x01000000;
/*Decrement yCounts by 2 since we already have 2 descriptors setup*/
yCounts -= 2;
/*Enable DMA interrupt*/
NVIC_EnableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
/*Initialize the channel with the first descriptor*/
Cy_DMA_Channel_SetDescriptor(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL , &readDesr0);
/*Enable the channel*/
Cy_DMA_Channel_Enable(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL );
/*Set the flag in the control register to enable the read*/
SDIO_CONTROL_REG |= SDIO_CTRL_ENABLE_READ;
}
/*Otherwise it is a write*/
else
{
/*First disable the Read channel*/
Cy_DMA_Channel_Disable(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL );
/*Clear any pending interrupts in the DMA*/
Cy_DMA_Channel_ClearInterrupt(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL);
NVIC_ClearPendingIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
/*setup the SRC addresses*/
writeDesr0.src = (uint32_t)(pstcDataConfig->pu8Data);
writeDesr1.src = (uint32_t)((pstcDataConfig->pu8Data) + 1024);
/*Setup the X control to transfer two 16 bit elements per transfer for a total of 4 bytes
Remember X increment is in terms of data element size which is 16, thus why it is 1*/
writeDesr0.xCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 1) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 1);
writeDesr1.xCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 1) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 1);
if (dataSize <= 1024)
{
/*Setup one descriptor*/
/*Y Increment is 2 because the X is transfer 2 data elements (which are 16 bits)*/
writeDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (dataSize - 1) / 4) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
/*Setup descriptor 0 to point to nothing and disable*/
writeDesr0.nextPtr = 0;
writeDesr0.ctl |= 0x01000000;
/*Disable Interrupt*/
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
else if (dataSize <=2048)
{
/*setup the first descriptor for 1024, then setup 2nd descriptor for remainder*/
writeDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 255) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
writeDesr1.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (dataSize - 1025) / 4) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
/*Setup descriptor 0 to point to descriptor 1*/
writeDesr0.nextPtr = (uint32_t)(&writeDesr1);
/*Setup descriptor 1 to point to nothing and disable */
writeDesr1.nextPtr = 0;
/*Don't disable after first descriptor*/
writeDesr0.ctl &= ~0x01000000;
/*Disable after second descriptor*/
writeDesr1.ctl |= 0x01000000;
/*Disable Interrupt*/
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
else /*dataSize must be greater than 2048*/
{
/*These are for the ISR, Need to figure out how many "descriptors"
need to run, and the yCount for last descriptor.
Example: dataSize = 2080
yCounts = 2, yCountRemainder = 7 (send 8 more set of 4)*/
yCounts = (dataSize / 1024);
/*the Ycount register is a +1 register meaning 0 = 1. I However, need to know when there is
no remainder so I increase the value to make sure there is a remainder and decrement in the ISR*/
yCountRemainder = (((dataSize - (yCounts * 1024)) + 3 ) / 4);
/*Setup the Y Ctrl for both descriptors*/
writeDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 255) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
writeDesr1.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, 255) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
/*Setup descriptor 0 to point to descriptor 1*/
writeDesr0.nextPtr = (uint32_t)(&writeDesr1);
/*Setup descriptor 1 to point to descriptor 0*/
writeDesr1.nextPtr = (uint32_t)(&writeDesr0);
/*Don't disable the channel on completion of descriptor*/
writeDesr0.ctl &= ~0x01000000;
writeDesr1.ctl &= ~0x01000000;
/*Decrement yCounts by 2 since we already have 2 descriptors setup*/
yCounts -= 2;
/*Enable DMA interrupt*/
NVIC_EnableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
/*Initialize the channel with the first descriptor*/
Cy_DMA_Channel_SetDescriptor(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL , &writeDesr0);
}
}
/*******************************************************************************
* Function Name: SDIO_SendCommandAndWait
****************************************************************************//**
*
* This function sends a command on the command channel and waits for that
* command to finish before returning. If a Command 53 is issued this function
* will handle all of the data transfer and wait to return until it is done.
*
* \param pstcCmd
* Pointer command configuration structure see \ref stc_sdio_cmd_t.
*
* \return
* \ref en_sdio_result_t
*
*******************************************************************************/
en_sdio_result_t SDIO_SendCommandAndWait(stc_sdio_cmd_t *pstcCmd)
{
/* Store the command and data configurations*/
stc_sdio_cmd_config_t stcCmdConfig;
stc_sdio_data_config_t stcDataConfig;
uint32_t u32CmdTimeout = 0;
/*Returns from various function calls*/
en_sdio_result_t enRet = Error;
en_sdio_result_t enRetTmp = Ok;
/* Hold value of if these checks are needed */
uint8_t bCmdIndexCheck;
uint8_t bCmdCrcCheck;
static uint8_t u8responseBuf[6];
/* Clear statuses */
gstcInternalData.stcEvents.u8CmdComplete = 0;
gstcInternalData.stcEvents.u8TransComplete = 0;
gstcInternalData.stcEvents.u8CRCError = 0;
/* Setup the command configuration */
stcCmdConfig.u8CmdIndex = (uint8_t)pstcCmd->u32CmdIdx;
stcCmdConfig.u32Argument = pstcCmd->u32Arg;
#ifdef CY_RTOS_AWARE
cy_rslt_t result;
/* Initialize the semaphore. This is not done in init because init is called
* in interrupt thread. cy_rtos_init_semaphore call is prohibited in
* interrupt thread.
*/
if(!sema_initialized)
{
cy_rtos_init_semaphore( &sdio_transfer_finished_semaphore, 1, 0 );
sema_initialized = true;
}
#else
/* Variable used for holding timeout value */
uint32_t u32Timeout = 0;
#endif
/*Determine the type of response and if we need to do any checks*/
/*Command 0 and 8 have no response, so don't wait for one*/
if (pstcCmd->u32CmdIdx == 0 || pstcCmd->u32CmdIdx == 8)
{
bCmdIndexCheck = false;
bCmdCrcCheck = false;
stcCmdConfig.bResponseRequired = false;
stcCmdConfig.pu8ResponseBuf = NULL;
}
/*Command 5's response doesn't have a CRC or index, so don't check*/
else if (pstcCmd->u32CmdIdx == 5)
{
bCmdIndexCheck = false;
bCmdCrcCheck = false;
stcCmdConfig.bResponseRequired = true;
stcCmdConfig.pu8ResponseBuf = u8responseBuf;
}
/*Otherwise check everything*/
else
{
bCmdIndexCheck = true;
bCmdCrcCheck = true;
stcCmdConfig.bResponseRequired = true;
stcCmdConfig.pu8ResponseBuf = u8responseBuf;
}
/*Check if the command is 53, if it is then setup the data transfer*/
if (pstcCmd->u32CmdIdx == 53)
{
/*Set the number of blocks in the global struct*/
stcDataConfig.u16BlockCount = (uint16_t)pstcCmd->u16BlockCnt;
/*Set the size of the data transfer*/
stcDataConfig.u16BlockSize = (uint16_t)pstcCmd->u16BlockSize;
/*Set the direction are we reading or writing*/
stcDataConfig.bRead = pstcCmd->bRead;
/*Set the pointer for the data*/
stcDataConfig.pu8Data = pstcCmd->pu8Data;
/*Get the data Transfer Ready*/
SDIO_InitDataTransfer(&stcDataConfig);
/*Set bit saying this was a CMD_53*/
SDIO_CONTROL_REG |= SDIO_CTRL_ENABLE_INT;
}
/*Send the command*/
SDIO_SendCommand(&stcCmdConfig);
/*Wait for the command to finish*/
do
{
u32CmdTimeout++;
enRetTmp = SDIO_CheckForEvent(SdCmdEventCmdDone);
} while ((enRetTmp != Ok) && (u32CmdTimeout < SDIO_CMD_TIMEOUT));
if (u32CmdTimeout == SDIO_CMD_TIMEOUT)
{
enRet |= CMDTimeout;
}
else /*CMD Passed*/
{
/*If a response is expected check it*/
if (stcCmdConfig.bResponseRequired == true)
{
enRetTmp = SDIO_GetResponse(bCmdCrcCheck, bCmdIndexCheck, (uint8_t)pstcCmd->u32CmdIdx, pstcCmd->pu32Response, u8responseBuf);
if (enRetTmp != Ok)
{
enRet |= enRetTmp;
}
else /*Response good*/
{
/*if it was command 53, check the response to ensure there was no error*/
if ((pstcCmd->u32CmdIdx) == 53)
{
/*Make sure none of the error bits are set*/
if (*(pstcCmd->pu32Response) & 0x0000cf00)
{
enRet |= ResponseFlagError;
}
else /*CMD53 Response good*/
{
/*If it was command 53 and it was a write enable the write*/
if (pstcCmd->bRead == false && enRet == Error)
{
Cy_DMA_Channel_Disable(SDIO_HOST_Resp_DMA_HW, SDIO_HOST_Resp_DMA_DW_CHANNEL );
Cy_DMA_Channel_Disable(SDIO_HOST_CMD_DMA_HW, SDIO_HOST_CMD_DMA_DW_CHANNEL );
Cy_DMA_Channel_Disable(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL );
/*Set the flag in the control register to enable the write*/
Cy_DMA_Channel_Enable(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL);
/*Enable the channel*/
Cy_SysLib_DelayCycles(35);
SDIO_CONTROL_REG |= SDIO_CTRL_ENABLE_WRITE;
}
#ifdef CY_RTOS_AWARE
/* Wait for the transfer to finish.
* Acquire semaphore and wait until it will be released
* in SDIO_IRQ:
* 1. sdio_transfer_finished_semaphore count is equal to
* zero. cy_rtos_get_semaphore waits until semaphore
* count is increased by cy_rtos_set_semaphore() in
* SDIO_IRQ.
* 2. The cy_rtos_set_semaphore() increases
* sdio_transfer_finished_semaphore count.
* 3. The cy_rtos_get_semaphore() function decreases
* sdio_transfer_finished_semaphore back to zero
* and exit. Or timeout occurs
*/
result = cy_rtos_get_semaphore( &sdio_transfer_finished_semaphore, 10, false );
enRetTmp = SDIO_CheckForEvent(SdCmdEventTransferDone);
if (result != CY_RSLT_SUCCESS)
#else
/* Wait for the transfer to finish */
do
{
u32Timeout++;
enRetTmp = SDIO_CheckForEvent(SdCmdEventTransferDone);
} while (!((enRetTmp == Ok) || (enRetTmp == DataCrcError) || (u32Timeout >= SDIO_DAT_TIMEOUT)));
if (u32Timeout == SDIO_DAT_TIMEOUT)
#endif
{
enRet |= DataTimeout;
}
/* if it was a read it is possible there is still extra data hanging out, trigger the
DMA again. This can result in extra data being transfered so the read buffer should be
3 bytes bigger than needed*/
if (pstcCmd->bRead == true)
{
Cy_TrigMux_SwTrigger((uint32_t)SDIO_HOST_Read_DMA_DW__TR_IN, 2);
}
if (enRetTmp == DataCrcError)
{
enRet |= DataCrcError;
}
}/*CMD53 response good*/
}/*Not a CMD53*/
} /*Response Good*/
} /*No Response Required, thus no CMD53*/
} /*CMD Passed*/
#ifndef CY_RTOS_AWARE
u32Timeout = 0;
#endif
/*If there were no errors then indicate transfer was okay*/
if (enRet == Error)
{
enRet = Ok;
}
/*reset CmdTimeout value*/
u32CmdTimeout = 0;
/*Always Reset on exit to clean up*/
Cy_DMA_Channel_Disable(SDIO_HOST_Resp_DMA_HW, SDIO_HOST_Resp_DMA_DW_CHANNEL );
Cy_DMA_Channel_Disable(SDIO_HOST_CMD_DMA_HW, SDIO_HOST_CMD_DMA_DW_CHANNEL );
Cy_DMA_Channel_Disable(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL );
Cy_DMA_Channel_Disable(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL );
/*No longer a CMD_53*/
SDIO_CONTROL_REG &= ~(SDIO_CTRL_ENABLE_INT | SDIO_CTRL_ENABLE_WRITE | SDIO_CTRL_ENABLE_READ);
SDIO_Reset();
return enRet;
}
/*******************************************************************************
* Function Name: SDIO_CheckForEvent
****************************************************************************//**
*
* Checks to see if a specific event has occurred such a command complete or
* transfer complete.
*
* \param enEventType
* The type of event to check for. See \ref en_sdio_event_t.
*
* \return
* \ref en_sdio_result_t
*
*******************************************************************************/
en_sdio_result_t SDIO_CheckForEvent(en_sdio_event_t enEventType)
{
en_sdio_result_t enRet = Error;
/*Disable Interrupts while modifying the global*/
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_sdio_int__INTC_NUMBER);
/*Switch the event to check*/
switch ( enEventType )
{
/*If the command is done clear the flag*/
case SdCmdEventCmdDone:
if (gstcInternalData.stcEvents.u8CmdComplete > 0)
{
gstcInternalData.stcEvents.u8CmdComplete = 0;
enRet = Ok;
}
break;
/*If the transfer is done check for CRC Error and clear the flag*/
case SdCmdEventTransferDone:
if (gstcInternalData.stcEvents.u8TransComplete > 0)
{
gstcInternalData.stcEvents.u8TransComplete = 0;
enRet = Ok;
}
/*Check for CRC error and set flags*/
if (gstcInternalData.stcEvents.u8CRCError > 0)
{
enRet = DataCrcError;
gstcInternalData.stcEvents.u8CRCError = 0;
}
break;
}
/*Re-enable Interrupts*/
NVIC_EnableIRQ((IRQn_Type) SDIO_HOST_sdio_int__INTC_NUMBER);
return enRet;
}
/*******************************************************************************
* Function Name: SDIO_CalculateCrc7
****************************************************************************//**
*
* Calculate the 7 bit CRC for the command channel
*
* \param pu8Data
* Data to calculate CRC on
*
* \param u8Size
* Number of bytes to calculate CRC on
*
* \return
* CRC
*
* \note
* This code was copied from
* http://www.barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
*
*******************************************************************************/
uint8_t SDIO_CalculateCrc7(uint8_t* pu8Data, uint8_t u8Size)
{
uint8_t data;
uint8_t remainder = 0;
uint32_t byte;
for(byte = 0; byte < u8Size; ++byte)
{
data = pu8Data[byte] ^ remainder;
remainder = crcTable[data] ^ (remainder << 8);
}
return (remainder>>1);
}
/*******************************************************************************
* Function Name: SDIO_Crc7Init
****************************************************************************//**
*
* Initialize 7-bit CRC Table
*
* \note
* This code was copied from
* http://www.barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
*
*******************************************************************************/
void SDIO_Crc7Init(void)
{
uint8_t remainder;
uint8_t bit;
uint32_t dividend;
for(dividend = 0; dividend < 256; ++dividend)
{
remainder = dividend;
for(bit = 8; bit > 0; --bit)
{
if (remainder & SDIO_CRC_UPPER_BIT)
{
remainder = (remainder << 1) ^ SDIO_CRC7_POLY;
}
else
{
remainder = (remainder << 1);
}
}
crcTable[dividend] = (remainder);
}
}
/*******************************************************************************
* Function Name: SDIO_SetBlockSize
****************************************************************************//**
*
* Sets the size of each block
*
* \param u8ByteCount
* Size of the block
*
*******************************************************************************/
void SDIO_SetBlockSize(uint8_t u8ByteCount)
{
SDIO_BYTE_COUNT_REG = u8ByteCount;
}
/*******************************************************************************
* Function Name: SDIO_SetNumBlocks
****************************************************************************//**
*
* Sets the number of blocks to send
*
* \param u8BlockCount
* Size of the block
*
*******************************************************************************/
void SDIO_SetNumBlocks(uint8_t u8BlockCount)
{
SDIO_DATA_BLOCK_COUNTER_A0_REG = u8BlockCount;
SDIO_DATA_BLOCK_COUNTER_D0_REG = u8BlockCount;
/*The one is used so that we can do 256 bytes*/
SDIO_DATA_BLOCK_COUNTER_A1_REG = 1;
SDIO_DATA_BLOCK_COUNTER_D1_REG = 1;
}
/*******************************************************************************
* Function Name: SDIO_EnableIntClock
****************************************************************************//**
*
* Enable Internal clock for the block
*
*******************************************************************************/
void SDIO_EnableIntClock(void)
{
SDIO_CONTROL_REG |= SDIO_CTRL_INT_CLK;
Cy_SysClk_PeriphEnableDivider(SDIO_HOST_Internal_Clock_DIV_TYPE, SDIO_HOST_Internal_Clock_DIV_NUM);
}
/*******************************************************************************
* Function Name: SDIO_DisableIntClock
****************************************************************************//**
*
* Enable Disable clock for the block
*
*******************************************************************************/
void SDIO_DisableIntClock(void)
{
SDIO_CONTROL_REG &= ~SDIO_CTRL_INT_CLK;
Cy_SysClk_PeriphDisableDivider(SDIO_HOST_Internal_Clock_DIV_TYPE, SDIO_HOST_Internal_Clock_DIV_NUM);
}
/*******************************************************************************
* Function Name: SDIO_EnableSdClk
****************************************************************************//**
*
* Enable SD Clock out to pin
*
*******************************************************************************/
void SDIO_EnableSdClk(void)
{
SDIO_CONTROL_REG |= SDIO_CTRL_SD_CLK;
}
/*******************************************************************************
* Function Name: SDIO_DisableSdClk
****************************************************************************//**
*
* Disable SD Clock out to the pin
*
*******************************************************************************/
void SDIO_DisableSdClk(void)
{
SDIO_CONTROL_REG &= ~SDIO_CTRL_SD_CLK;
}
/*******************************************************************************
* Function Name: SDIO_SetSdClkFrequency
****************************************************************************//**
*
* Sets the frequency of the SD Clock
*
* \param u32SdClkFreqHz
* Frequency of SD Clock in Hz.
*
* \note
* Only an integer divider is used, so the desired frequency may not be meet
*******************************************************************************/
void SDIO_SetSdClkFrequency(uint32_t u32SdClkFreqHz)
{
uint16_t u16Div;
/*
* The UDB SDIO implemenation has a extra divider internally that divides the input clock to the UDB
* by 2. The desired clock frequency is hence intentionally multiplied by 2 in order to get the required
* SDIO operating frequency.
*/
u16Div = Cy_SysClk_ClkPeriGetFrequency() / (2 * u32SdClkFreqHz);
Cy_SysClk_PeriphSetDivider(SDIO_HOST_Internal_Clock_DIV_TYPE, SDIO_HOST_Internal_Clock_DIV_NUM, (u16Div-1));
}
/*******************************************************************************
* Function Name: SDIO_SetupDMA
****************************************************************************//**
*
* Configures the DMA for the SDIO block
*
*******************************************************************************/
void SDIO_SetupDMA(void)
{
/*Set the number of bytes to send*/
SDIO_HOST_CMD_DMA_CMD_DMA_Desc_config.xCount = (SDIO_NUM_RESP_BYTES - 1);
/*Set the destination address*/
SDIO_HOST_CMD_DMA_CMD_DMA_Desc_config.dstAddress = (void*)SDIO_CMD_COMMAND_PTR;
/*Initialize descriptor for cmd channel*/
Cy_DMA_Descriptor_Init(&cmdDesr, &SDIO_HOST_CMD_DMA_CMD_DMA_Desc_config);
/*Set flag to disable descriptor when done*/
cmdDesr.ctl |= 0x01000000;
/*Configure channel*/
/*CMD channel can be preempted, and has lower priority*/
cmdChannelConfig.descriptor = &cmdDesr;
cmdChannelConfig.preemptable = 1;
cmdChannelConfig.priority = 1;
cmdChannelConfig.enable = 0u;
/*Configure Channel with initial Settings*/
Cy_DMA_Channel_Init(SDIO_HOST_CMD_DMA_HW, SDIO_HOST_CMD_DMA_DW_CHANNEL, &cmdChannelConfig);
/*Enable DMA block*/
Cy_DMA_Enable(SDIO_HOST_CMD_DMA_HW);
/*Set the number of bytes to receive*/
SDIO_HOST_Resp_DMA_Resp_DMA_Desc_config.xCount = SDIO_NUM_RESP_BYTES;
/*Set the source address*/
SDIO_HOST_Resp_DMA_Resp_DMA_Desc_config.srcAddress = (void*)SDIO_CMD_RESPONSE_PTR;
/*Initialize descriptor for response channel*/
Cy_DMA_Descriptor_Init(&respDesr, &SDIO_HOST_Resp_DMA_Resp_DMA_Desc_config);
/*Set flag to disable descriptor when done*/
respDesr.ctl |= 0x01000000;
/*Configure channel*/
/*response channel can be preempted, and has lower priority*/
respChannelConfig.descriptor = &respDesr;
respChannelConfig.preemptable = 1;
respChannelConfig.priority = 1;
respChannelConfig.enable = 0u;
/*Configure Channel with initial Settings*/
Cy_DMA_Channel_Init(SDIO_HOST_Resp_DMA_HW, SDIO_HOST_Resp_DMA_DW_CHANNEL, &respChannelConfig);
/*Enable DMA block*/
Cy_DMA_Enable(SDIO_HOST_Resp_DMA_HW);
/*Set the destination address*/
SDIO_HOST_Write_DMA_Write_DMA_Desc_config.dstAddress = (void*)SDIO_DAT_WRITE_PTR;
/*Initialize descriptor for write channel*/
Cy_DMA_Descriptor_Init(&writeDesr0, &SDIO_HOST_Write_DMA_Write_DMA_Desc_config);
Cy_DMA_Descriptor_Init(&writeDesr1, &SDIO_HOST_Write_DMA_Write_DMA_Desc_config);
/*Configure channel*/
/*write channel cannot be preempted, and has highest priority*/
writeChannelConfig.descriptor = &writeDesr0;
writeChannelConfig.preemptable = 0;
writeChannelConfig.priority = 0;
writeChannelConfig.enable = 0u;
/*Configure Channel with initial Settings*/
Cy_DMA_Channel_Init(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL, &writeChannelConfig);
/*Enable the interrupt*/
Cy_DMA_Channel_SetInterruptMask(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL,CY_DMA_INTR_MASK);
/*Enable DMA block*/
Cy_DMA_Enable(SDIO_HOST_Write_DMA_HW);
/*Set the source address*/
SDIO_HOST_Read_DMA_Read_DMA_Desc_config.srcAddress = (void*)SDIO_DAT_READ_PTR;
/*Initialize descriptor for read channel*/
Cy_DMA_Descriptor_Init(&readDesr0, &SDIO_HOST_Read_DMA_Read_DMA_Desc_config);
Cy_DMA_Descriptor_Init(&readDesr1, &SDIO_HOST_Read_DMA_Read_DMA_Desc_config);
/*Configure channel*/
/*read channel cannot be preempted, and has highest priority*/
readChannelConfig.descriptor = &readDesr0;
readChannelConfig.preemptable = 0;
readChannelConfig.priority = 0;
readChannelConfig.enable = 0u;
/*Configure Channel with initial Settings*/
Cy_DMA_Channel_Init(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL, &readChannelConfig);
/*Enable the interrupt*/
Cy_DMA_Channel_SetInterruptMask(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL,CY_DMA_INTR_MASK);
/*Enable DMA block*/
Cy_DMA_Enable(SDIO_HOST_Read_DMA_HW);
}
/*******************************************************************************
* Function Name: SDIO_Reset
****************************************************************************//**
*
* Reset the SDIO interface
*
*******************************************************************************/
void SDIO_Reset(void)
{
/*Control register is in pulse mode, so this just pulses the reset*/
SDIO_CONTROL_REG |= (SDIO_CTRL_RESET_DP);
}
/*******************************************************************************
* Function Name: SDIO_EnableChipInt
****************************************************************************//**
*
* Enables the SDIO Chip Int by setting the mask bit
*
*******************************************************************************/
void SDIO_EnableChipInt(void)
{
SDIO_STATUS_INT_MSK |= SDIO_STS_CARD_INT;
}
/*******************************************************************************
* Function Name: SDIO_DisableChipInt
****************************************************************************//**
*
* Enables the SDIO Chip Int by setting the mask bit
*
*******************************************************************************/
void SDIO_DisableChipInt(void)
{
SDIO_STATUS_INT_MSK &= ~SDIO_STS_CARD_INT;
}
/*******************************************************************************
* Function Name: SDIO_IRQ
****************************************************************************//**
*
* SDIO interrupt, checks for events, and calls callbacks
*
*******************************************************************************/
void SDIO_IRQ(void)
{
uint8_t u8Status;
/* First read the status register */
u8Status = SDIO_STATUS_REG;
/* Check card interrupt */
if (u8Status & SDIO_STS_CARD_INT )
{
pfnCardInt_count++;
}
/* Execute card interrupt callback if neccesary */
if (0 != pfnCardInt_count)
{
if (NULL != gstcInternalData.pstcCallBacks.pfnCardIntCb)
{
gstcInternalData.pstcCallBacks.pfnCardIntCb();
}
pfnCardInt_count--;
}
/* If the command is complete set the flag */
if (u8Status & SDIO_STS_CMD_DONE)
{
gstcInternalData.stcEvents.u8CmdComplete++;
}
/* Check if a write is complete */
if (u8Status & SDIO_STS_WRITE_DONE )
{
/* Clear the Write flag and CMD53 flag */
SDIO_CONTROL_REG &= ~(SDIO_CTRL_ENABLE_WRITE | SDIO_CTRL_ENABLE_INT);
/* Check if the CRC status return was bad */
if (u8Status & SDIO_STS_CRC_ERR)
{
/* CRC was bad, set the flag */
gstcInternalData.stcEvents.u8CRCError++;
}
/* Set the done flag */
#ifdef CY_RTOS_AWARE
cy_rtos_set_semaphore( &sdio_transfer_finished_semaphore, true );
#else
gstcInternalData.stcEvents.u8TransComplete++;
#endif
}
/* Check if a read is complete */
if (u8Status & SDIO_STS_READ_DONE)
{
/* Clear the read flag */
SDIO_CONTROL_REG &= ~(SDIO_CTRL_ENABLE_READ| SDIO_CTRL_ENABLE_INT);
/* Check the CRC */
if (u8Status & SDIO_STS_CRC_ERR)
{
/* CRC was bad, set the flag */
gstcInternalData.stcEvents.u8CRCError++;
}
/* Okay we're done so set the done flag */
#ifdef CY_RTOS_AWARE
cy_rtos_set_semaphore( &sdio_transfer_finished_semaphore, true );
#else
gstcInternalData.stcEvents.u8TransComplete++;
#endif
}
NVIC_ClearPendingIRQ((IRQn_Type) SDIO_HOST_sdio_int__INTC_NUMBER);
}
/*******************************************************************************
* Function Name: SDIO_READ_DMA_IRQ
****************************************************************************//**
*
* SDIO DMA Read interrupt, checks counts and toggles to other descriptor if
* needed
*
*******************************************************************************/
void SDIO_READ_DMA_IRQ(void)
{
/*Shouldn't have to change anything unless it is the last descriptor*/
/*If the current descriptor is 0, then change descriptor 1*/
if (Cy_DMA_Channel_GetCurrentDescriptor(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL) == &readDesr0)
{
/*We need to increment the destination address every time*/
readDesr1.dst += 2048;
/*If this is the last descriptor*/
if ((yCounts == 1) && (yCountRemainder == 0))
{
/* In this case all we need to change is the next descriptor and disable*/
readDesr1.nextPtr = 0;
readDesr1.ctl |= 0x01000000;
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
else if (yCounts == 0 && (yCountRemainder > 0))
{
/*change next descriptor, and disable*/
readDesr1.nextPtr = 0;
readDesr1.ctl |= 0x01000000;
/*Also change the yCount*/
readDesr1.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (yCountRemainder-1)) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
}
/*If the current descriptor is 1, then change descriptor 0*/
if (Cy_DMA_Channel_GetCurrentDescriptor(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL) == &readDesr1)
{
/*We need to increment the destination address everytime*/
readDesr0.dst += 2048;
/*If this is the last descriptor*/
if ((yCounts == 1) && (yCountRemainder == 0))
{
/* In this case all we need to change is the next descriptor and disable*/
readDesr0.nextPtr = 0;
readDesr0.ctl |= 0x01000000;
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
else if (yCounts == 0 && (yCountRemainder > 0))
{
/*change next descriptor, and disable*/
readDesr0.nextPtr = 0;
readDesr0.ctl |= 0x01000000;
/*Also change the yCount*/
readDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (yCountRemainder-1)) |
_VAL2FLD(CY_DMA_CTL_DST_INCR, 2);
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Read_Int_INTC_NUMBER);
}
}
/*Clear the interrupt*/
Cy_DMA_Channel_ClearInterrupt(SDIO_HOST_Read_DMA_HW, SDIO_HOST_Read_DMA_DW_CHANNEL);
/*decrement y counts*/
yCounts--;
}
/*******************************************************************************
* Function Name: SDIO_WRITE_DMA_IRQ
****************************************************************************//**
*
* SDIO DMA Write interrupt, checks counts and toggles to other descriptor if
* needed
*
*******************************************************************************/
void SDIO_WRITE_DMA_IRQ(void)
{
/*We shouldn't have to change anything unless it is the last descriptor*/
/*If the current descriptor is 0, then change descriptor 1*/
if (Cy_DMA_Channel_GetCurrentDescriptor(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL) == &writeDesr0)
{
/*We also need to increment the destination address every-time*/
writeDesr1.src += 2048;
/*If this is the last descriptor*/
if ((yCounts == 1) && (yCountRemainder == 0))
{
/* In this case all we need to change is the next descriptor and disable*/
writeDesr1.nextPtr = 0;
writeDesr1.ctl |= 0x01000000;
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
else if (yCounts == 0 && (yCountRemainder > 0))
{
/*change next descriptor, and disable*/
writeDesr1.nextPtr = 0;
writeDesr1.ctl |= 0x01000000;
/*Also change the yCount*/
writeDesr1.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (yCountRemainder -1)) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
}
/*If the current descriptor is 1, then change descriptor 0*/
if (Cy_DMA_Channel_GetCurrentDescriptor(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL) == &writeDesr1)
{
/*We also need to increment the destination address*/
writeDesr0.src += 2048;
/*If this is the last descriptor*/
if ((yCounts == 1) && (yCountRemainder == 0))
{
/* In this case all we need to change is the next descriptor and disable*/
writeDesr0.nextPtr = 0;
writeDesr0.ctl |= 0x01000000;
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
else if (yCounts == 0 && (yCountRemainder > 0))
{
/*change next descriptor, and disable*/
writeDesr0.nextPtr = 0;
writeDesr0.ctl |= 0x01000000;
/*Also change the yCount*/
writeDesr0.yCtl = _VAL2FLD(CY_DMA_CTL_COUNT, (yCountRemainder -1)) |
_VAL2FLD(CY_DMA_CTL_SRC_INCR, 2);
NVIC_DisableIRQ((IRQn_Type) SDIO_HOST_Write_Int_INTC_NUMBER);
}
}
/*Clear the interrupt*/
Cy_DMA_Channel_ClearInterrupt(SDIO_HOST_Write_DMA_HW, SDIO_HOST_Write_DMA_DW_CHANNEL);
yCounts--;
}
/*******************************************************************************
* Function Name: SDIO_Free
****************************************************************************//**
*
* Frees any system resources that were allocated by the SDIO driver.
*
*******************************************************************************/
void SDIO_Free(void)
{
#ifdef CY_RTOS_AWARE
cy_rtos_deinit_semaphore(&sdio_transfer_finished_semaphore);
#endif
}
/*******************************************************************************
* Function Name: SDIO_SaveConfig
********************************************************************************
*
* Saves the user configuration of the SDIO UDB non-retention registers. Call the
* SDIO_SaveConfig() function before the Cy_SysPm_CpuEnterDeepSleep() function.
*
*******************************************************************************/
static void SDIO_SaveConfig(void)
{
regs.CY_SDIO_UDB_WRKMULT_CTL_0 = UDB->WRKMULT.CTL[0];
regs.CY_SDIO_UDB_WRKMULT_CTL_1 = UDB->WRKMULT.CTL[1];
regs.CY_SDIO_UDB_WRKMULT_CTL_2 = UDB->WRKMULT.CTL[2];
regs.CY_SDIO_UDB_WRKMULT_CTL_3 = UDB->WRKMULT.CTL[3];
}
/*******************************************************************************
* Function Name: SDIO_RestoreConfig
********************************************************************************
*
* Restores the user configuration of the SDIO UDB non-retention registers. Call
* the SDIO_Wakeup() function after the Cy_SysPm_CpuEnterDeepSleep() function.
*
*******************************************************************************/
static void SDIO_RestoreConfig(void)
{
UDB->WRKMULT.CTL[0] = regs.CY_SDIO_UDB_WRKMULT_CTL_0;
UDB->WRKMULT.CTL[1] = regs.CY_SDIO_UDB_WRKMULT_CTL_1;
UDB->WRKMULT.CTL[2] = regs.CY_SDIO_UDB_WRKMULT_CTL_2;
UDB->WRKMULT.CTL[3] = regs.CY_SDIO_UDB_WRKMULT_CTL_3;
}
#if defined(__cplusplus)
}
#endif
#endif /* defined(CYHAL_UDB_SDIO) */
/* [] END OF FILE */