//Initialize the specified channel. Reserve A and B pins (not the IO pins)
//countMode X1=1, X2=2, X4=3
HRESULT	QED_Initialize		(int channel, int countMode) {
	if (channel != 0)
		return CLR_E_INVALID_PARAMETER;
	if (countMode < 1 || countMode > 3)
		return CLR_E_INVALID_PARAMETER;
	//Reserve PA0 and PA1
	if (CPU_GPIO_ReservePin(0, TRUE) == false) 
		return CLR_E_PIN_UNAVAILABLE;
	if (CPU_GPIO_ReservePin(1, TRUE) == false) 
		return CLR_E_PIN_UNAVAILABLE;
	//Power port A (should be already done in bootstrap) and TIM2
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
	//PA0 and PA1 mode alternate: 10b
	GPIOA->MODER &= ~(GPIO_MODER_MODER1 | GPIO_MODER_MODER0);
	GPIOA->MODER |= (GPIO_MODER_MODER1_1 | GPIO_MODER_MODER0_1);
	//Alternate function AF1 : TIM2 input for PA1 and PA0
	GPIOA->AFR[0] &= ~0x000000FF;
	GPIOA->AFR[0] |= 0x00000011;
	//pull up
	GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR1);
	GPIOA->PUPDR |= (GPIO_PUPDR_PUPDR0_0 | GPIO_PUPDR_PUPDR1_0);
	TIM2->CR2 = 0;
	//external clock enable
	TIM2->SMCR |= TIM_SMCR_ECE;
	//Encoder X mode count 
	TIM2->SMCR &= ~TIM_SMCR_SMS;
	TIM2->SMCR |= countMode;
	//if (countMode == 3)
	//	TIM2->SMCR |= TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0;	//X4
	//else 
	//	TIM2->SMCR |= TIM_SMCR_SMS_1;	//X2 on PA0
	//filter N=8
	TIM2->SMCR &= ~TIM_SMCR_ETF;
	TIM2->SMCR |= TIM_SMCR_ETF_1 | TIM_SMCR_ETF_0;
	//no polarity invertion, rising edge
	TIM2->CCER = 0;
	//Count up to 32bits
	TIM2->ARR = 0xFFFFFFFF;

	for (int IOIndex = 0; IOIndex < 2; IOIndex++) {
		g_completion[IOIndex].InitializeForISR(&PulseCompletionHandler, (void*)IOIndex);
		g_pulseLength[IOIndex] = 0;
		g_IOStatus[IOIndex] = IOStatus_None; 
	}
	//activate interrupt and enable counter
	CPU_INTC_ActivateInterrupt(TIM2_IRQn, STM32F4_TIM2_Interrupt, 0);
	TIM2->CR1 |= TIM_CR1_CEN;

	return S_OK;
}
Beispiel #2
0
void HAL_UnReserveAllGpios()
{
    for(INT32 i = CPU_GPIO_GetPinCount()-1; i >=0; i--)
    {
        CPU_GPIO_ReservePin((GPIO_PIN)i, false);
    }
}
//Unitialize the specified channel
void	QED_Uninitialize	(int channel) {
	if (channel !=0) 
		return;	
	GLOBAL_LOCK(irq);
	//disable counter and interrupt
	QED_SetCountEnable(0, FALSE);
	CPU_INTC_DeactivateInterrupt(TIM2_IRQn);
	//release A and B pins
	CPU_GPIO_ReservePin(0, FALSE);
	CPU_GPIO_ReservePin(1, FALSE);
	for (int IOIndex = 0; IOIndex < 2; IOIndex++) {
		//release IO pins and discard capture/compare
		QED_ReleaseIO(0, IOIndex);
		g_completion[IOIndex].Uninitialize();
	}

}
//Release the specified IO pin if reserved by QED_InitOutputCompare() or QED_InitInputCapture()
void	QED_ReleaseIO(int channel, int IOIndex) {
	if (channel != 0)
		return;
	if (IOIndex < 0 || IOIndex > 1)
		return;
	if (g_IOStatus[IOIndex] != IOStatus_None) {
		if (IOIndex == 0) {
			//no capture/compare selection
			TIM2->CCMR2 &= ~TIM_CCMR2_CC3S;
			//disable capture compare 
			TIM2->CCER &= ~TIM_CCER_CC3E;
		}
		else if (IOIndex == 1) {
			TIM2->CCMR2 &= ~TIM_CCMR2_CC4S;
			TIM2->CCER &= ~TIM_CCER_CC4E;
		}
		CPU_GPIO_ReservePin(QED_GetIOPinForChannel(channel, IOIndex), FALSE);
		g_IOStatus[IOIndex] = IOStatus_None; 
		g_pulseLength[IOIndex] = 0;
	}
}
Beispiel #5
0
void __section("SectionForBootstrapOperations") BootstrapCode_GPIO()
{
    /* GPIO pins connected to NOR Flash and SRAM on the MCBSTM32F400 board */
    const uint8_t PortD_PinList[] = {0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12 ,13, 14, 15};
#ifdef DEBUG
    // PE2,3,4,5 are used for TRACECLK and TRACEDATA0-3 so don't enable them as address pins in debug builds
    // This limits external FLASH and SRAM to 1MB addressable space each.
    const uint8_t PortE_PinList[] = {0, 1, /*2, 3, 4, 5,*/ 7, 8, 9, 10, 11, 12, 13, 14, 15};
#else
    const uint8_t PortE_PinList[] = {0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15};
#endif
    const uint8_t PortF_PinList[] = {0, 1, 2, 3, 4, 5, 12, 13, 14, 15};
    const uint8_t PortG_PinList[] = {0, 1, 2, 3, 4, 5, 10};
    
    const uint32_t pinConfig = 0x3C2;    // Speed 100Mhz, AF12 FSMC, Alternate Mode
    const uint32_t pinMode = pinConfig & 0xF;
    const GPIO_ALT_MODE alternateMode = (GPIO_ALT_MODE) pinConfig;
    const GPIO_RESISTOR resistorConfig = RESISTOR_PULLUP;
    
    uint32_t i;

    /* Enable GPIO clocks */  
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN
                  | RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN
                  | RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN | RCC_AHB1ENR_GPIOIEN;

    CPU_GPIO_EnableOutputPin(LED1, FALSE);
    CPU_GPIO_EnableOutputPin(LED2, FALSE); 
    CPU_GPIO_EnableOutputPin(LED3, FALSE); 
    CPU_GPIO_EnableOutputPin(LED4, FALSE); 
    CPU_GPIO_EnableOutputPin(LED5, FALSE);
    CPU_GPIO_EnableOutputPin(LED6, FALSE);
    CPU_GPIO_EnableOutputPin(LED7, FALSE);
    CPU_GPIO_EnableOutputPin(LED8, FALSE);
    
    /*Initialize SRAM and NOR GPIOs */
    for(i = 0; i < ARRAY_LENGTH(PortD_PinList); i++)    /* Port D */
    {
        CPU_GPIO_ReservePin( PORT_PIN(GPIO_PORTD, PortD_PinList[i]), TRUE);
        CPU_GPIO_DisablePin( PORT_PIN(GPIO_PORTD, PortD_PinList[i]),  resistorConfig, 0, alternateMode);
        STM32F4_GPIO_Pin_Config( PORT_PIN(GPIO_PORTD, PortD_PinList[i]), pinMode, resistorConfig, pinConfig ); // Workaround, since CPU_GPIO_DisablePin() does not correctly initialize pin speeds
    }
    
    for(i = 0; i < ARRAY_LENGTH(PortE_PinList); i++)    /* Port E */
    {
        CPU_GPIO_ReservePin( PORT_PIN(GPIO_PORTE, PortE_PinList[i]), TRUE);
        CPU_GPIO_DisablePin( PORT_PIN(GPIO_PORTE, PortE_PinList[i]),  resistorConfig, 0, alternateMode);
        STM32F4_GPIO_Pin_Config( PORT_PIN(GPIO_PORTE, PortE_PinList[i]), pinMode, resistorConfig, pinConfig ); // Workaround, since CPU_GPIO_DisablePin() does not correctly initialize pin speeds
    }
    
    for(i = 0; i < ARRAY_LENGTH(PortF_PinList); i++)    /* Port F */
    {
        CPU_GPIO_ReservePin( PORT_PIN(GPIO_PORTF, PortF_PinList[i]), TRUE);
        CPU_GPIO_DisablePin( PORT_PIN(GPIO_PORTF, PortF_PinList[i]),  resistorConfig, 0, alternateMode);
        STM32F4_GPIO_Pin_Config( PORT_PIN(GPIO_PORTF, PortF_PinList[i]), pinMode, resistorConfig, pinConfig ); // Workaround, since CPU_GPIO_DisablePin() does not correctly initialize pin speeds
    }
    
    for(i = 0; i < ARRAY_LENGTH(PortG_PinList); i++)    /* Port G */
    {
        CPU_GPIO_ReservePin( PORT_PIN(GPIO_PORTG, PortG_PinList[i]), TRUE);
        CPU_GPIO_DisablePin( PORT_PIN(GPIO_PORTG, PortG_PinList[i]),  resistorConfig, 0, alternateMode);
        STM32F4_GPIO_Pin_Config( PORT_PIN(GPIO_PORTG, PortG_PinList[i]), pinMode, resistorConfig, pinConfig ); // Workaround, since CPU_GPIO_DisablePin() does not correctly initialize pin speeds
    }
    
    /* Initialize NOR and SRAM */
    InitNorFlash();
    InitSram();
}
//Initialize the specified IO for input capture on raising edge or falling edge if invert is true
//Reserve the IO pin at first call
HRESULT	QED_InitInputCapture(int channel, int IOIndex, BOOL invert, QED_EVENT onInputCapture) {
	if (channel != 0)
		return CLR_E_INVALID_PARAMETER;
	if (IOIndex < 0 || IOIndex > 1)
		return CLR_E_INVALID_PARAMETER;
	if (g_IOStatus[IOIndex] == IOStatus_OutputCompare) 
		return CLR_E_PIN_UNAVAILABLE;
	if (g_IOStatus[IOIndex] == IOStatus_None) {
		if (CPU_GPIO_ReservePin(QED_GetIOPinForChannel(channel, IOIndex), TRUE) == false) 
			return CLR_E_PIN_UNAVAILABLE;
		g_IOStatus[IOIndex] = IOStatus_InputCapture;
	}
	if (IOIndex == 0) {
		//disable capture/compare
		TIM2->CCER &= ~TIM_CCER_CC3E;
		//PA2 mode alternate: 10b
		GPIOA->MODER &= ~GPIO_MODER_MODER2;
		GPIOA->MODER |= GPIO_MODER_MODER2_1;
		//Alternate function AF1 : TIM2 CH3 for PA2
		GPIOA->AFR[0] &= ~0x00000F00;
		GPIOA->AFR[0] |= 0x00000100;
		//pull up
		GPIOA->PUPDR &= ~ GPIO_PUPDR_PUPDR2;
		GPIOA->PUPDR |= GPIO_PUPDR_PUPDR2_0;
		//capture on ch3
		TIM2->CCMR2 &= ~TIM_CCMR2_CC3S;
		TIM2->CCMR2 |= TIM_CCMR2_CC3S_0;
		//input filter N=8
		TIM2->CCMR2 &= ~TIM_CCMR2_IC3F;
		TIM2->CCMR2 |= TIM_CCMR2_IC3F_1 | TIM_CCMR2_IC3F_0;
		//no prescaler
		TIM2->CCMR2 &= ~TIM_CCMR2_IC3PSC;
		//non inverting/rising edge
		TIM2->CCER &= ~TIM_CCER_CC3NP;
		if (invert) {
			//inverting/falling edge
			TIM2->CCER &= ~TIM_CCER_CC3P;
		}
		else {
			//non inverting/rising edge
			TIM2->CCER &= ~TIM_CCER_CC3P;
		}
		//no DMA
		TIM2->DIER &= ~TIM_DIER_CC3DE;
		//enabled
		TIM2->CCER |= TIM_CCER_CC3E;
	} else if (IOIndex == 1) {
		//disable capture/compare
		TIM2->CCER &= ~TIM_CCER_CC4E;
		//PA3 mode alternate: 10b
		GPIOA->MODER &= ~GPIO_MODER_MODER3;
		GPIOA->MODER |= GPIO_MODER_MODER3_1;
		//Alternate function AF1 : TIM2 CH4 for PA3
		GPIOA->AFR[0] &= ~0x0000F000;
		GPIOA->AFR[0] |= 0x00001000;
		//pull up
		GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR3;
		GPIOA->PUPDR |= GPIO_PUPDR_PUPDR3_0;
		//capture on ch4 pins
		TIM2->CCMR2 &= ~TIM_CCMR2_CC4S;
		TIM2->CCMR2 |= TIM_CCMR2_CC4S_0;
		//input filter N=8
		TIM2->CCMR2 &= ~TIM_CCMR2_IC4F;
		TIM2->CCMR2 |= TIM_CCMR2_IC4F_1 | TIM_CCMR2_IC4F_0;
		//no prescaler
		TIM2->CCMR2 &= ~TIM_CCMR2_IC4PSC;
		//polarity
		TIM2->CCER &= ~TIM_CCER_CC4NP;
		if (invert) {
			//inverting/falling edge
			TIM2->CCER &= ~TIM_CCER_CC4P;
		}
		else {
			//non inverting/rising edge
			TIM2->CCER &= ~TIM_CCER_CC4P;
		}
		//no DMA
		TIM2->DIER &= ~TIM_DIER_CC4DE;
		//capture enabled
		TIM2->CCER |= TIM_CCER_CC4E;
	}
	g_pulseLength[IOIndex] = 0;
	g_eventCallback[IOIndex] = onInputCapture;
	return S_OK;
}
//Initialize the specified IO for output compare, negative pulse if invert is true
//pulseLength=0 means infinite pulse
//Reserve the IO pin and set the output state at first call, support successive calls (do not set the output state if not first call)
HRESULT	QED_InitOutputCompare(int channel, int IOIndex, int value, BOOL invert, int pulseLength, QED_EVENT onOutputCompare) {
	if (channel != 0)
		return CLR_E_INVALID_PARAMETER;
	if (IOIndex < 0 || IOIndex > 1)
		return CLR_E_INVALID_PARAMETER;
	if (g_IOStatus[IOIndex] == IOStatus_InputCapture) 
		return CLR_E_PIN_UNAVAILABLE;
	if (g_IOStatus[IOIndex] == IOStatus_None) {
		GPIO_PIN IOPin = QED_GetIOPinForChannel(channel, IOIndex);
		if (CPU_GPIO_ReservePin(IOPin, TRUE) == false) 
			return CLR_E_PIN_UNAVAILABLE;
		g_IOStatus[IOIndex] = IOStatus_OutputCompare;
	}
	if (IOIndex == 0) {
		//disable capture/compare
		TIM2->CCER &= ~TIM_CCER_CC3E;
		//PA3 mode alternate: 10b
		GPIOA->MODER &= ~GPIO_MODER_MODER2;
		GPIOA->MODER |= GPIO_MODER_MODER2_1;
		//Alternate function AF1 : TIM2 CH3 for PA2
		GPIOA->AFR[0] &= ~0x00000F00;
		GPIOA->AFR[0] |= 0x00000100;
		//set compare on ch3
		TIM2->CCMR2 &= ~TIM_CCMR2_CC3S;
		//set output on match
		TIM2->CCMR2 &= ~TIM_CCMR2_OC3M;
		TIM2->CCMR2 |= TIM_CCMR2_OC3M_0;
		//polarity
		if (invert)
			TIM2->CCER |= TIM_CCER_CC3P;
		else 
			TIM2->CCER &= ~TIM_CCER_CC3P;
		//init comparison value
		TIM2->CCR3 = value;
		//enable output
		TIM2->CCER |= TIM_CCER_CC3E;
		//enable interrupt, no DMA
		TIM2->DIER |= TIM_DIER_CC3IE;
		TIM2->DIER &= ~TIM_DIER_CC3DE;
	}
	else if (IOIndex == 1) {
		//disable capture/compare
		TIM2->CCER &= ~TIM_CCER_CC4E;
		//PA3 mode alternate: 10b
		GPIOA->MODER &= ~GPIO_MODER_MODER3;
		GPIOA->MODER |= GPIO_MODER_MODER3_1;
		//Alternate function AF1 : TIM2 CH4 for PA3
		GPIOA->AFR[0] &= ~0x0000F000;
		GPIOA->AFR[0] |= 0x00001000;
		//set compare on ch4
		TIM2->CCMR2 &= ~TIM_CCMR2_CC4S;
		//set output on match
		TIM2->CCMR2 &= ~TIM_CCMR2_OC4M;
		TIM2->CCMR2 |= TIM_CCMR2_OC4M_0;
		//polarity
		if (invert)
			TIM2->CCER |= TIM_CCER_CC4P;
		else 
			TIM2->CCER &= ~TIM_CCER_CC4P;
		//init comparison value
		TIM2->CCR4 = value;
		//enable output
		TIM2->CCER |= TIM_CCER_CC4E;
		//enable interrupt, no DMA
		TIM2->DIER |= TIM_DIER_CC4IE;
		TIM2->DIER &= ~TIM_DIER_CC4DE;
	}
	//init output state at first call or if precedent setting was infinite pulse length
	if (g_pulseLength[IOIndex] == 0)
		QED_ResetOutput(IOIndex);
	g_pulseLength[IOIndex] = pulseLength;
	g_eventCallback[IOIndex] = onOutputCompare;
	return S_OK;
}
BOOL SD_BS_Driver::ChipInitialize(void *context)
{
    SD_BLOCK_CONFIG *config = (SD_BLOCK_CONFIG*)context;

    if(!config || !config->BlockDeviceInformation)
    {
        return FALSE;
    }

    BlockDeviceInfo *pDevInfo = config->BlockDeviceInformation;

	UINT32 alternate = 0x1C2;

	CPU_GPIO_DisablePin(PC8_SD_D0, RESISTOR_PULLUP, 0, (GPIO_ALT_MODE)alternate);
	CPU_GPIO_DisablePin(PC9_SD_D1, RESISTOR_PULLUP, 0, (GPIO_ALT_MODE)alternate);
	CPU_GPIO_DisablePin(PC10_SD_D2, RESISTOR_PULLUP, 0, (GPIO_ALT_MODE)alternate);
	CPU_GPIO_DisablePin(PC11_SD_D3, RESISTOR_PULLUP, 0, (GPIO_ALT_MODE)alternate);
	CPU_GPIO_DisablePin(PC12_SD_CLK, RESISTOR_DISABLED, 0, (GPIO_ALT_MODE)alternate);
	CPU_GPIO_DisablePin(PD2_SD_CMD, RESISTOR_PULLUP, 0, (GPIO_ALT_MODE)alternate);

	CPU_GPIO_ReservePin( PC8_SD_D0, TRUE );
	CPU_GPIO_ReservePin( PC9_SD_D1, TRUE );
	CPU_GPIO_ReservePin( PC10_SD_D2, TRUE );
	CPU_GPIO_ReservePin( PC11_SD_D3, TRUE );
	CPU_GPIO_ReservePin( PC12_SD_CLK, TRUE );
	CPU_GPIO_ReservePin( PD2_SD_CMD, TRUE );

	RCC->APB2ENR |= (1 << 11);
	CPU_INTC_ActivateInterrupt( /*UINT32 Irq_Index*/SDIO_IRQn, /*HAL_CALLBACK_FPN ISR*/SDIO_IRQHandler, /*void* ISR_Param*/0 );

	__IO SD_Error errorstatus = SD_OK;
	//errorstatus = SD_PowerON();
	errorstatus = SD_Init();

	CPU_INTC_InterruptEnable( /*UINT32 Irq_Index*/SDIO_IRQn );

	memset(pBuffer, 0xFF, 512);
	errorstatus = SD_ReadBlock(pBuffer, 0, 512);
	//errorstatus = SD_WaitReadOperation();
	//while(SD_GetStatus() != SD_TRANSFER_OK);
   if (SD_GetStatus() != SD_TRANSFER_OK)
   {
      if (SD_GetStatus_WithTimeOut(SD_INITIALIZE_TIMEOUT)== FALSE) 
        return FALSE;
   }


	//CPU_FlushCaches();

//	// Variables to setup SD Card Dynamically.
//	//BYTE regCSD[16];   <-- Not used because we have better register access.

    BYTE C_SIZE_MULT = 0;

    BYTE TAAC, NSAC, MAX_RAN_SPEED, READ_BL_LEN, SECTOR_SIZE;

    BOOL ERASE_BL_EN;

    UINT32 C_SIZE;

    UINT64 MemCapacity = 0; //total memory size, in unit of byte

    TAAC			= SDCardInfo.SD_csd.TAAC; // regCSD[1]; /* STM // Original */
    NSAC			= SDCardInfo.SD_csd.NSAC; // regCSD[2]; /* STM // Original */
	MAX_RAN_SPEED	= SDCardInfo.SD_csd.MaxBusClkFrec; // regCSD[3]; /* STM // Original */
    READ_BL_LEN		= SDCardInfo.SD_csd.RdBlockLen; // regCSD[5] &0x0F; /* STM // Original */

	// Checks to see if the SD card is Version 1.0: Standard or Version 2.0: High Capacity
	if(SDCardInfo.SD_csd.CSDStruct == 0x00)  /*if(regCSD[0] == 0x00)*/
	// SD Version1.0
	{
		C_SIZE = SDCardInfo.SD_csd.DeviceSize; // ((regCSD[6] &0x3) << 10) | (regCSD[7] << 2) | ((regCSD[8] &0xC0) >> 6); /* STM // Original */

		C_SIZE_MULT = SDCardInfo.SD_csd.DeviceSizeMul; // ((regCSD[9] &0x03) << 1) | ((regCSD[10] &0x80) >> 7); /* STM // Original */

		ERASE_BL_EN = (SDCardInfo.SD_csd.EraseGrSize == 0x00) ? FALSE : TRUE; // ((regCSD[10] &0x40) == 0x00) ? FALSE : TRUE; /* STM // Original */

		SECTOR_SIZE = SDCardInfo.SD_csd.EraseGrMul; // ((regCSD[10] &0x3F) << 1) | ((regCSD[11] &0x80) >> 7); /* STM // Original */

		MemCapacity = SDCardInfo.CardCapacity; // (C_SIZE + 1) * (0x1 << (C_SIZE_MULT + 2)) * (0x1 << READ_BL_LEN); /* STM // Original */

		IsSDCardHC = FALSE;
	}
	else
	// SD Version2.0
	{
		C_SIZE = SDCardInfo.SD_csd.DeviceSize; // ((regCSD[7] &0x3F) << 16) | (regCSD[8] << 8) | regCSD[9]; /* STM // Original */

		ERASE_BL_EN = (SDCardInfo.SD_csd.EraseGrSize == 0x00) ? FALSE : TRUE; // ((regCSD[10] &0x40) == 0x00) ? FALSE : TRUE; /* STM // Original */

		SECTOR_SIZE = SDCardInfo.SD_csd.EraseGrMul; // ((regCSD[10] &0x3F) << 1) | ((regCSD[11] &0x80) >> 7); /* STM // Original */

		MemCapacity = SDCardInfo.CardCapacity; // (C_SIZE + 1) * 512 * 1024; /* STM // Original */

		IsSDCardHC = TRUE;
	}
    //Update SD config according to CSD register
    UINT32 SectorsPerBlock    = (ERASE_BL_EN == TRUE) ? 1 : (SECTOR_SIZE + 1);
    pDevInfo->BytesPerSector  = 512; // data bytes per sector is always 512
	pDevInfo->Size            = (ByteAddress)MemCapacity;

    BlockRegionInfo* pRegions = (BlockRegionInfo*)&pDevInfo->Regions[0];
    pRegions[0].BytesPerBlock = SectorsPerBlock * pDevInfo->BytesPerSector;
    pRegions[0].NumBlocks     = (UINT32)(MemCapacity / pRegions[0].BytesPerBlock);
        
    BlockRange* pRanges   = (BlockRange*)&pRegions[0].BlockRanges[0];

    pRanges[0].StartBlock = 0;
    pRanges[0].EndBlock   = pRegions[0].NumBlocks-1;

    return TRUE;
}