Example #1
0
/**************************************************************************//**
 * @brief  Setup the ACMP
 *****************************************************************************/
void setupACMP(void)
{
  /* ACMP configuration constant table. */
  static const ACMP_Init_TypeDef initACMP =
  {
    .fullBias = false,                 /* fullBias */
    .halfBias = true,                  /* halfBias */
    .biasProg =  0x0,                  /* biasProg */
    .interruptOnFallingEdge =  false,  /* interrupt on rising edge */
    .interruptOnRisingEdge =  false,   /* interrupt on falling edge */
    //.interruptOnFallingEdge =  true,  /* interrupt on rising edge */
    //.interruptOnRisingEdge =  true,   /* interrupt on falling edge */
    .warmTime = acmpWarmTime4,       /* 512 cycle warmup to be safe */
    .hysteresisLevel = acmpHysteresisLevel0, /* No Hysteresis */
    .inactiveValue = false,            /* inactive value */
    .lowPowerReferenceEnabled = true, /* low power reference */
    .vddLevel = 32,                  /* VDD level : VDD/2 */
    .enable = false                    /* Don't request enabling. */
  };


  /* Configure ACMP. */
  ACMP_Init(ACMP1, &initACMP);
  /* Disable ACMP0 out to a pin. */
  ACMP_GPIOSetup(ACMP1, 0, false, false);
  /* Set up ACMP negSel to VDD, posSel is controlled by LESENSE. */
  ACMP_ChannelSet(ACMP1, acmpChannelVDD, acmpChannel0);
  /* LESENSE controls ACMP thus ACMP_Enable(ACMP0) should NOT be called in order
   * to ensure lower current consumption. */

#ifdef DEBUG_ACMP
  ACMP_ChannelSet(ACMP1, acmpChannelVDD, acmpChannel2);
  ACMP1->IEN = 1;
  ACMP_Enable(ACMP1);
  NVIC_ClearPendingIRQ(ACMP0_IRQn);
  NVIC_EnableIRQ(ACMP0_IRQn);
#endif
}

#ifdef DEBUG_ACMP
// ACMP IRQ Handler is shared between ACMP0 and ACMP1
void ACMP0_IRQHandler(void)
{
  PRINTF("%s\r\n",__func__);
  ACMP1->IFC = 1;
  NVIC_ClearPendingIRQ(ACMP0_IRQn);
}
Example #2
0
/**************************************************************************//**
 * @brief This function iterates through all the capsensors and reads and
 *        initiates a reading. Uses EM1 while waiting for the result from
 *        each sensor.
 *****************************************************************************/
void CAPSENSE_Sense(void)
{
  /* Use the default STK capacative sensing setup and enable it */
  ACMP_Enable(ACMP_CAPSENSE);

  uint8_t ch;
  /* Iterate trough all channels */
  for (currentChannel = 0; currentChannel < ACMP_CHANNELS; currentChannel++)
  {
    /* If this channel is not in use, skip to the next one */
    if (!channelsInUse[currentChannel])
    {
      continue;
    }

    /* Set up this channel in the ACMP. */
    ch = currentChannel;
    ACMP_CapsenseChannelSet(ACMP_CAPSENSE, (ACMP_Channel_TypeDef) ch);

    /* Reset timers */
    TIMER0->CNT = 0;
    TIMER1->CNT = 0;

    measurementComplete = false;

    /* Start timers */
    TIMER0->CMD = TIMER_CMD_START;
    TIMER1->CMD = TIMER_CMD_START;

    /* Wait for measurement to complete */
    while ( measurementComplete == false )
    {
      EMU_EnterEM1();
    }
  }

  /* Disable ACMP while not sensing to reduce power consumption */
  ACMP_Disable(ACMP_CAPSENSE);
}
/**************************************************************************//**
 * @brief  ACMP_setup
 * Configures and starts the ACMP
 *****************************************************************************/
void ACMP_setup(void)
{
  /* Enable necessary clocks */
  CMU_ClockEnable(cmuClock_ACMP0, true);
  CMU_ClockEnable(cmuClock_GPIO, true);

  /* Configure PC4 as input with pull down for ACMP channel 4 input */
  GPIO_PinModeSet(gpioPortC, 4, gpioModeInputPullFilter, 0);

  /* Analog comparator parameters */
  const ACMP_Init_TypeDef acmpInit =
  {
    .fullBias                 = false,                  /* no full bias current*/
    .halfBias                 = false,                  /* no half bias current */
    .biasProg                 = 7,                      /* Biasprog current 1.4 uA */
    .interruptOnFallingEdge   = false,                  /* disable interrupt for falling edge */
    .interruptOnRisingEdge    = false,                  /* disable interrupt for rising edge */
    .warmTime                 = acmpWarmTime256,        /* Warm-up time in clock cycles, should be >140 cycles for >10us warm-up @ 14MHz */
    .hysteresisLevel          = acmpHysteresisLevel0,   /* Hysteresis level 0  - no hysteresis */
    .inactiveValue            = 0,                      /* Inactive comparator output value */
    .lowPowerReferenceEnabled = false,                  /* Low power reference mode disabled */
    .vddLevel                 = 32,                     /* Vdd reference scaling of 32 */
  };

  /* Init ACMP and set ACMP channel 4 as positive input
     and scaled Vdd as negative input */
  ACMP_Init(ACMP0, &acmpInit);
  ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel4);
  ACMP_Enable(ACMP0);
}

/**************************************************************************//**
 * @brief  PRS_ScanChannel
 * Waits for activity on a selected PRS channel and writes on the LCD 
   when activity occurs
 *  
 * @param[in] timer  
 *   Pointer to TIMER peripheral register block.
 *
 * @param[in] prsCh
 * 	 PRS Channel to be monitored
 *
 * @param[in] edgeType
 *   Signal edge to be monitored/captured 
 *****************************************************************************/
void PRS_ScanChannel(TIMER_TypeDef *timer, TIMER_PRSSEL_TypeDef prsCh, TIMER_Edge_TypeDef edgeType)
{
  
/* enable the clock for the correct timer */  
#define TIMER_Clock(T) (T==TIMER0 ? cmuClock_TIMER0 : \
                          T==TIMER1 ? cmuClock_TIMER1 : 0)
  
  /* Enable necessary clocks */
  CMU_ClockEnable((CMU_Clock_TypeDef)TIMER_Clock(timer), true);
    
  /* Initialize LCD */
  SegmentLCD_Init(false);

  /* Select CC channel parameters */
  const TIMER_InitCC_TypeDef timerCCInit = 
  {
    .eventCtrl  = timerEventFalling,      /* input capture event control */
    .edge       = edgeType,               /* input capture on falling edge */
    .prsSel     = prsCh,                  /* prs channel select channel 5*/
    .cufoa      = timerOutputActionNone,  /* no action on counter underflow */
    .cofoa      = timerOutputActionNone,  /* no action on counter overflow */
    .cmoa       = timerOutputActionNone,  /* no action on counter match */
    .mode       = timerCCModeCapture,     /* CC channel mode capture */
    .filter     = false,                  /* no filter */
    .prsInput   = true,                   /* CC channel PRS input */
    .coist      = false,                  /* comparator output initial state */
    .outInvert  = false,                  /* no output invert */
  };
  
  /* Initialize TIMER0 CC0 */
  TIMER_InitCC(timer, 0, &timerCCInit);
  
  /* Select timer parameters */  
  const TIMER_Init_TypeDef timerInit =
  {
    .enable     = true,                         /* start counting when init complete */         
    .debugRun   = false,                        /* counter not running on debug halt */  
    .prescale   = timerPrescale1024,            /* prescaler of 64 */
    .clkSel     = timerClkSelHFPerClk,          /* TIMER0 clocked by the HFPERCLK */
    .fallAction = timerInputActionNone,         /* stop counter on falling edge */
    .riseAction = timerInputActionNone,         /* reload and start on rising edge */
    .mode       = timerModeUp,                  /* counting up */
    .dmaClrAct  = false,                        /* no DMA */
    .quadModeX4 = false,                        /* no quad decoding */
    .oneShot    = false,                        /* counting up constinuously */
    .sync       = false,                        /* no start/stop/reload by other timers */
  };
  
  /* Initialize TIMER0 */
  TIMER_Init(timer, &timerInit);  
  
  /* Poll the Input Capture Valid flag in the Status register
      The program will hang at this point waiting for activity on this
	  channel */
  while(!((TIMER0->STATUS & _TIMER_STATUS_ICV0_MASK )>>16));  
}

/**************************************************************************//**
 * @brief  Main function
 * Main is called from __iar_program_start, see assembly startup file
 *****************************************************************************/
int main(void)
{
  /* Align different chip revisions*/
  CHIP_Init();
  
  /* Initialise the ACMP */
  ACMP_setup();

  /* PRS setup */
  /* Enable clock for PRS and select ACMP as source and ACMP0OUT (ACMP0 OUTPUT) as signal 
     for channel 5 */
  CMU_ClockEnable(cmuClock_PRS, true);
  PRS_SourceSignalSet(5, PRS_CH_CTRL_SOURCESEL_ACMP0, PRS_CH_CTRL_SIGSEL_ACMP0OUT, prsEdgeOff);
  
  /* Start PRS scan 
     This function will halt the program while there is no PRS activity
     This function assumes that the PRS has been setup previously */
  PRS_ScanChannel(TIMER0, timerPRSSELCh5, timerEdgeFalling);
  
  /* Write PRS and channel number on the LCD to acknowledge PRS activity */  
  SegmentLCD_Write("PRS");
  SegmentLCD_Number((int)timerPRSSELCh5);
  
  while(1)
  {
    /* Enter EM1 while waiting for capture. */
    EMU_EnterEM1();
  }
}
Example #4
0
/**************************************************************************//**
 * @brief  TIMER0_setup
 * Configures the TIMER
 *****************************************************************************/
void TIMER_setup(void)
{
  /* Enable necessary clocks */
  CMU_ClockEnable(cmuClock_TIMER0, true);
  CMU_ClockEnable(cmuClock_PRS, true);

  /* Select CC channel parameters */
  TIMER_InitCC_TypeDef timerCCInit =
  {
    .eventCtrl  = timerEventEveryEdge,      /* Input capture event control */
    .edge       = timerEdgeBoth,       /* Input capture on falling edge */
    .prsSel     = timerPRSSELCh5,         /* Prs channel select channel 5*/
    .cufoa      = timerOutputActionNone,  /* No action on counter underflow */
    .cofoa      = timerOutputActionNone,  /* No action on counter overflow */
    .cmoa       = timerOutputActionNone,  /* No action on counter match */
    .mode       = timerCCModeCapture,     /* CC channel mode capture */
    .filter     = false,                  /* No filter */
    .prsInput   = true,                   /* CC channel PRS input */
    .coist      = false,                  /* Comparator output initial state */
    .outInvert  = false,                  /* No output invert */
  };

  /* Initialize TIMER0 CC0 channel */
  TIMER_InitCC(HIJACK_RX_TIMER, 0, &timerCCInit);

  /* Select timer parameters */
  const TIMER_Init_TypeDef timerInit =
  {
    .enable     = false,                        /* Do not start counting when init complete */
    .debugRun   = false,                        /* Counter not running on debug halt */
    .prescale   = HIJACK_TIMER_RESOLUTION,      /* Prescaler of 1 */
    .clkSel     = timerClkSelHFPerClk,          /* TIMER0 clocked by the HFPERCLK */
    .fallAction = timerInputActionReloadStart,         /* Stop counter on falling edge */
    .riseAction = timerInputActionReloadStart,  /* Reload and start on rising edge */
    .mode       = timerModeUp,                  /* Counting up */
    .dmaClrAct  = false,                        /* No DMA */
    .quadModeX4 = false,                        /* No quad decoding */
    .oneShot    = false,                        /* Counting up constinuously */
    .sync       = false,                        /* No start/stop/reload by other timers */
  };

  /* Initialize TIMER0 */
  TIMER_Init(HIJACK_RX_TIMER, &timerInit);

  /* PRS setup */
  /* Select ACMP as source and ACMP0OUT (ACMP0 OUTPUT) as signal */
  PRS_SourceSignalSet(5, PRS_CH_CTRL_SOURCESEL_ACMP0, PRS_CH_CTRL_SIGSEL_ACMP0OUT, prsEdgeOff);

  /* Enable CC0 interrupt */
  TIMER_IntEnable(HIJACK_RX_TIMER, TIMER_IF_CC0);

  /* Enable TIMER0 interrupt vector in NVIC */
  NVIC_EnableIRQ(TIMER0_IRQn);
}

/**************************************************************************//**
 * @brief  ACMP_setup
 * Configures and starts the ACMP
 *****************************************************************************/
static void ACMP_setup(void)
{
  /* Enable necessary clocks */
  CMU_ClockEnable(HIJACK_RX_ACMPCLK, true);
  CMU_ClockEnable(cmuClock_GPIO, true);

  /* Configure ACMP input pin. */
  GPIO_PinModeSet(HIJACK_RX_GPIO_PORT, HIJACK_RX_GPIO_PIN, gpioModeInput, 0);

  /* Analog comparator parameters */
  const ACMP_Init_TypeDef acmpInit =
  {
    .fullBias                 = false,                  /* No full bias current*/
    .halfBias                 = true,                  /* No half bias current */
    .biasProg                 = 2,                      /* Biasprog current 1.4 uA */
    .interruptOnFallingEdge   = false,                  /* Disable interrupt for falling edge */
    .interruptOnRisingEdge    = false,                  /* Disable interrupt for rising edge */
    .warmTime                 = acmpWarmTime256,        /* Warm-up time in clock cycles, should be >140 cycles for >10us warm-up @ 14MHz */
    .hysteresisLevel          = acmpHysteresisLevel7,   /* Hysteresis level 0  - no hysteresis */
    .inactiveValue            = 1,                      /* Inactive comparator output value */
    .lowPowerReferenceEnabled = false,                  /* Low power reference mode disabled */
    .vddLevel                 = HIJACK_RX_ACMP_LEVEL,                     /* Vdd reference scaling of 32 */
  };

  /* Use ACMP0 output, PD6 . */
  //GPIO_PinModeSet(gpioPortD, 6, gpioModePushPull, 0);
  //ACMP_GPIOSetup(ACMP0, 2, true, false);

  /* Init ACMP and set ACMP channel 4 as positive input
     and scaled Vdd as negative input */
  ACMP_Init(HIJACK_RX_ACMP, &acmpInit);
  ACMP_ChannelSet(HIJACK_RX_ACMP, HIJACK_RX_ACMP_NEG, HIJACK_RX_ACMP_CH);
  ACMP_Enable(HIJACK_RX_ACMP);
}

/**
 * @brief calculate whether cnt is in 500us region
 * ticker = 64Mhz/128 = 2us
 * 475us < cnt < 510us
 *
 */
static chk_result_t IsTime2Detect(uint32_t inv)
{
  	chk_result_t ret;
	
  	if( inv < HIJACK_DEC_NUM_TICKS_MIN){
    	offset = inv;
	    ret = pass;
  	}
	else if ( ( inv <= HIJACK_DEC_NUM_TICKS_MAX ) && ( inv >= HIJACK_DEC_NUM_TICKS_MIN ) ) {
		offset = 0;
		inv = 0;
	  	ret = suit;
	}
	else{
		offset = 0;
		inv = 0;
		ret = error;
	}
	return ret;
}

/*
 * Find phase remain or phase reversal.
*/

static void dec_parser(uint8_t bit_msk, state_t state)
{
  	if ( ( suit == IsTime2Detect(inv) ) ){ //it's time to determine
		if( falling == cur_edge ){
	  		dec.data &= ~(1 << bit_msk);
#if DEC_DEBUG == 1
			uartPutChar( '+' ) ;
			uartPutChar( '_' ) ;
#endif//DEC_DEBUG == 1
		}
		else{
		   	dec.data |= (1 << bit_msk);
#if DEC_DEBUG == 1
			uartPutChar( '_' ) ;
			uartPutChar( '+' ) ;
#endif//DEC_DEBUG == 1
			dec.odd++;
		}
		dec.state = state;   //state switch
	}
	else if ( error == IsTime2Detect(inv) ){   //wait for edge detection time
		dec.state = Waiting;   //state switch
	}
}
/**************************************************************************//**
 * @brief  decode state machine
 * Invoke in TIMER_ISR for decoding.
 *****************************************************************************/
void decode_machine(void)
{
   	inv = offset + cur_stamp;  //update offset
#if 0
	if( dec.state > Waiting ){
	  	USART_printHexBy16u(inv);
		if(cur_edge == rising){
			uartPutChar( '\\' ) ;
		}
		else{
			uartPutChar( '/' ) ;
		}
	}
#endif	
	switch (dec.state){
		case Waiting:
         	/* go to start bit if rising edge exist. */
         	if (rising == cur_edge) {
            	dec.state = Sta0;
            	offset = 0;
				inv = 0;
         	}
			break;
			//
		case Sta0:
         	if( ( suit == IsTime2Detect(inv) ) && ( falling == cur_edge ) ){
				dec.data = 0;  //clear data field for store new potential data
				dec.odd = 0;   //clear odd field parity counter
				dec.state = Bit0;
#if DEC_DEBUG == 1
			  	uartPutChar( 'S' ) ;
				uartPutChar( '+' ) ;
				uartPutChar( '_' ) ;
#endif
         	}
			else{
				dec.state = Waiting;
			}
	   		break;
			//
		case Bit0:
#if DEC_DEBUG == 1
			uartPutChar( '0' ) ;
#endif
		  	dec_parser(BIT0, Bit1);
	   		break;
			//
		case Bit1:
#if DEC_DEBUG == 1
			uartPutChar( '1' ) ;
#endif
		  	dec_parser(BIT1, Bit2);
	   		break;
			//
		case Bit2:
#if DEC_DEBUG == 1
			uartPutChar( '2' ) ;
#endif
		  	dec_parser(BIT2, Bit3);
	   		break;
			//
		case Bit3:
#if DEC_DEBUG == 1
			uartPutChar( '3' ) ;
#endif
		  	dec_parser(BIT3, Bit4);
	   		break;
			//
		case Bit4:
#if DEC_DEBUG == 1
			uartPutChar( '4' ) ;
#endif
		  	dec_parser(BIT4, Bit5);
	   		break;
			//
		case Bit5:
#if DEC_DEBUG == 1
			uartPutChar( '5' ) ;
#endif
		  	dec_parser(BIT5, Bit6);
	   		break;
			//
		case Bit6:
#if DEC_DEBUG == 1
			uartPutChar( '6' ) ;
#endif
		  	dec_parser(BIT6, Bit7);
	   		break;
			//
		case Bit7:
#if DEC_DEBUG == 1
			uartPutChar( '7' ) ;
#endif
		  	dec_parser(BIT7, Parity);
	   		break;
			//
		case Parity:		
			if ( ( suit == IsTime2Detect(inv) ) ){ //it's time to determine
				if( rising == cur_edge ){
				   dec.odd++;
#if DEC_DEBUG == 1
				   uartPutChar( '_' ) ;
				   uartPutChar( '+' ) ;
#endif
				}
				else{
#if DEC_DEBUG == 1
				   uartPutChar( '+' ) ;
				 	uartPutChar( '_' ) ;
#endif					
				}
#if DEC_DEBUG == 1
					uartPutChar( dec.odd + 0x30) ;
#endif
				if( 1 == (dec.odd%2)){  //parity pass
				   dec.state = Sto0;
				}
				else{ //parity failed
				   dec.state = Waiting;
				}
			 }
			 else if ( error == IsTime2Detect(inv) ){   //wait for edge detection time
				dec.state = Waiting;
			 }
			break;
			//
      	case Sto0:	
         	if ( ( suit == IsTime2Detect(inv) ) ){ //it's time to determine
				if( rising == cur_edge ){  //stop bit is rising edge
				    USART_txByte(dec.data);
#if DEC_DEBUG == 1
					uartPutChar( '_' ) ;
				    uartPutChar( '+' ) ;
#endif
				    HIJACKPutData(&dec.data, &decBuf, sizeof(uint8_t));
				}
				else{
#if DEC_DEBUG == 1
				  	uartPutChar( '+' ) ;
				 	uartPutChar( '_' ) ;
#endif			
				}
				dec.state = Waiting;
#if DEC_DEBUG == 1
				uartPutChar( '\r' ) ;
				uartPutChar( '\n' ) ;
#endif
         	}
         	else if ( error == IsTime2Detect(inv) ){   //wait for edge detection time
				dec.state = Waiting;
			}
         	break;
         	//
		default:
	  		break;
			//
	}
}