OSStatus host_platform_sdio_transfer( bus_transfer_direction_t direction, sdio_command_t command, sdio_transfer_mode_t mode, sdio_block_size_t block_size, uint32_t argument, /*@null@*/ uint32_t* data, uint16_t data_size, sdio_response_needed_t response_expected, /*@out@*/ /*@null@*/ uint32_t* response ) { uint32_t loop_count = 0; OSStatus result; uint16_t attempts = 0; check_string(!((command == SDIO_CMD_53) && (data == NULL)), "Bad args" ); if ( response != NULL ) { *response = 0; } platform_mcu_powersave_disable(); /* Ensure the bus isn't stuck half way through transfer */ DMA2_Stream3->CR = 0; restart: SDIO->ICR = (uint32_t) 0xFFFFFFFF; sdio_transfer_failed = false; ++attempts; /* Check if we've tried too many times */ if (attempts >= (uint16_t) BUS_LEVEL_MAX_RETRIES) { result = kGeneralErr; goto exit; } /* Prepare the data transfer register */ current_command = command; if ( command == SDIO_CMD_53 ) { sdio_enable_bus_irq(); /* Dodgy STM32 hack to set the CMD53 byte mode size to be the same as the block size */ if ( mode == SDIO_BYTE_MODE ) { block_size = find_optimal_block_size( data_size ); if ( block_size < SDIO_512B_BLOCK ) { argument = ( argument & (uint32_t) ( ~0x1FF ) ) | block_size; } else { argument = ( argument & (uint32_t) ( ~0x1FF ) ); } } /* Prepare the SDIO for a data transfer */ current_transfer_direction = direction; sdio_prepare_data_transfer( direction, block_size, (uint8_t*) data, data_size ); /* Send the command */ SDIO->ARG = argument; SDIO->CMD = (uint32_t) ( command | SDIO_Response_Short | SDIO_Wait_No | SDIO_CPSM_Enable ); /* Wait for the whole transfer to complete */ result = mico_rtos_get_semaphore( &sdio_transfer_finished_semaphore, (uint32_t) 50 ); if ( result != kNoErr ) { goto exit; } if ( sdio_transfer_failed == true ) { goto restart; } /* Check if there were any SDIO errors */ require(( SDIO->STA & ( SDIO_STA_DTIMEOUT | SDIO_STA_CTIMEOUT ) ) == 0, restart); require_string(( SDIO->STA & ( SDIO_STA_CCRCFAIL | SDIO_STA_DCRCFAIL | SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR ) ) == 0, restart, "SDIO communication failure"); /* Wait till complete */ loop_count = (uint32_t) SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS; do { loop_count--; if ( loop_count == 0 || ( ( SDIO->STA & SDIO_ERROR_MASK ) != 0 ) ) { goto restart; } } while ( ( SDIO->STA & ( SDIO_STA_TXACT | SDIO_STA_RXACT ) ) != 0 ); if ( direction == BUS_READ ) { memcpy( user_data, dma_data_source, (size_t) user_data_size ); } } else { uint32_t temp_sta; /* Send the command */ SDIO->ARG = argument; SDIO->CMD = (uint32_t) ( command | SDIO_Response_Short | SDIO_Wait_No | SDIO_CPSM_Enable ); loop_count = (uint32_t) COMMAND_FINISHED_CMD52_TIMEOUT_LOOPS; do { temp_sta = SDIO->STA; loop_count--; if ( loop_count == 0 || ( ( response_expected == RESPONSE_NEEDED ) && ( ( temp_sta & SDIO_ERROR_MASK ) != 0 ) ) ) { goto restart; } } while ( ( temp_sta & SDIO_FLAG_CMDACT ) != 0 ); } if ( response != NULL ) { *response = SDIO->RESP1; } result = kNoErr; exit: platform_mcu_powersave_enable(); #ifndef SDIO_1_BIT SDIO->MASK = SDIO_MASK_SDIOITIE; #endif return result; }
wwd_result_t host_platform_sdio_transfer( wwd_bus_transfer_direction_t direction, sdio_command_t command, sdio_transfer_mode_t mode, sdio_block_size_t block_size, uint32_t argument, /*@null@*/ uint32_t* data, uint16_t data_size, sdio_response_needed_t response_expected, /*@out@*/ /*@null@*/ uint32_t* response ) { uint8_t error; MciCmd *pCommand = &( sdio_command ); platform_mcu_powersave_disable(); /* direction => BUS_READ, BUS_WRITE, command => SDIO_CMD_0, SDIO_CMD_3, SDIO_CMD_5, SDIO_CMD_7, SDIO_CMD_52, SDIO_CMD_53 mode => SDIO_BLOCK_MODE, SDIO_BYTE_MODE block_size => SDIO_1B_BLOCK to SDIO_2048B_BLOCK, we use SDIO_1B_BLOCK and SDIO_64B_BLOCK argument => data byte (or 0) response_expected => RESPONSE_NEEDED, NO_RESPONSE */ UNUSED_PARAMETER( response_expected ); reset_sdio_command( pCommand ); //fill defaults pCommand->arg = argument; pCommand->pResp = response; //clear the response, if any if ( response != NULL) { *response = 0; }; // note: do not forget to properly fill Rx response reg. number to pCommand->resType //do the command switch ( command ) { case SDIO_CMD_0: { //CMD 0: typical direction: BUS_WRITE pCommand->cmd = ( 0 | HSMCI_CMDR_RSPTYP_48_BIT | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_TRCMD_NO_DATA | HSMCI_CMDR_MAXLAT); //pCommand->resType = 1; // nah error = send_sdio_command( &sdio_driver, 1 ); if ( error == 0 ) { platform_mcu_powersave_enable(); return WICED_SUCCESS; }; break; } case SDIO_CMD_3: { //CMD 3: typical direction: BUS_READ pCommand->cmd = 3; pCommand->cmd |= HSMCI_CMDR_RSPTYP_48_BIT; pCommand->cmd |= HSMCI_CMDR_SPCMD_STD; pCommand->cmd |= HSMCI_CMDR_OPDCMD_OPENDRAIN; pCommand->cmd |= HSMCI_CMDR_MAXLAT_64; pCommand->cmd |= HSMCI_CMDR_TRCMD_NO_DATA; pCommand->cmd |= (direction==BUS_READ)?HSMCI_CMDR_TRDIR_READ:HSMCI_CMDR_TRDIR_WRITE; pCommand->cmd |= HSMCI_CMDR_TRTYP_BYTE; pCommand->cmd |= HSMCI_CMDR_IOSPCMD_STD; pCommand->cmd |= HSMCI_CMDR_ATACS_NORMAL; pCommand->resType = 6; error = send_sdio_command( &sdio_driver, 0 ); if ( error == SDMMC_ERROR_NORESPONSE ) { platform_mcu_powersave_enable(); return WICED_TIMEOUT; } else if ( error == 0 ) { platform_mcu_powersave_enable(); return WICED_SUCCESS; }; break; } case SDIO_CMD_5: { //CMD 5: typical direction: BUS_READ pCommand->cmd = ( 5 | HSMCI_CMDR_RSPTYP_R1B | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT | HSMCI_CMDR_TRCMD_NO_DATA ); pCommand->resType = 4; error = send_sdio_command( &sdio_driver, 1 ); if ( error == 0 ) { platform_mcu_powersave_enable(); return WICED_SUCCESS; }; break; } case SDIO_CMD_7: { //CMD 7: typical direction: BUS_WRITE pCommand->cmd = ( 7 | HSMCI_CMDR_RSPTYP_R1B | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT | HSMCI_CMDR_TRCMD_NO_DATA ); pCommand->resType = 1; error = send_sdio_command( &sdio_driver, 1 ); if ( error == 0 ) { platform_mcu_powersave_enable(); return WICED_SUCCESS; }; break; } case SDIO_CMD_52: { //CMD 52: typical direction: BOTH pCommand->cmd = ( 52 | HSMCI_CMDR_RSPTYP_48_BIT | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT | HSMCI_CMDR_TRCMD_NO_DATA ); pCommand->resType = 5; error = send_sdio_command( &sdio_driver, 1 ); if ( error == 0 ) { platform_mcu_powersave_enable(); return WICED_SUCCESS; }; break; } case SDIO_CMD_53: { //specific pCommand->cmd = ( 53 | HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_RSPTYP_48_BIT | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT ); /* Write/Read operation */ if ( direction == BUS_WRITE ) { pCommand->tranType = MCI_START_WRITE; } else { pCommand->cmd |= HSMCI_CMDR_TRDIR; pCommand->tranType = MCI_START_READ; } /* Always Block mode */ pCommand->cmd |= HSMCI_CMDR_TRTYP_BLOCK | HSMCI_CMDR_TRCMD_START_DATA; if ( mode == SDIO_BYTE_MODE ) { /* Dodgy STM32 hack to set the CMD53 byte mode size to be the same as the block size */ pCommand->cmd |= HSMCI_CMDR_TRTYP_BYTE; block_size = find_optimal_block_size( data_size ); if ( block_size < SDIO_512B_BLOCK ) { pCommand->arg = ( pCommand->arg & (uint32_t) ( ~0x1FF ) ) | block_size; } else { pCommand->arg = ( pCommand->arg & (uint32_t) ( ~0x1FF ) ); } // compute block count pCommand->blockSize = block_size; pCommand->nbBlock = ( data_size / block_size ); if ( ( pCommand->nbBlock * block_size ) < data_size ) { pCommand->nbBlock++; }; } else { // compute block count pCommand->blockSize = block_size; pCommand->nbBlock = ( data_size / block_size ); if ( ( pCommand->nbBlock * block_size ) < data_size ) { pCommand->nbBlock++; }; } pCommand->resType = 5; //select the response register /* Set the DMA data pointer to the temp data for SDIO read */ if ( direction == BUS_WRITE ) { pCommand->pData = (unsigned char *)data; } else { pCommand->pData = (unsigned char *)temp_sdio_rx_buffer; } error = send_sdio_command( &sdio_driver, 0 ); if ( error == 0 ) { if ( direction == BUS_READ ) { /* Copy the data read by DMA to the buffer */ memcpy( (void *) data, (void *) temp_sdio_rx_buffer, data_size ); } platform_mcu_powersave_enable(); return WICED_SUCCESS; } break; } case __MAX_VAL: break; default: // WICED_ERROR_PRINT_DEBUG_ONLY(( "\n INVALID SDIO CMD \n" )); break; } platform_mcu_powersave_enable(); return WICED_ERROR; }