Пример #1
0
// Set the frequency of the generated tone. 0 means off.
void audioFrequencySet(uint32_t freq) {
	// In order to avoid audio hiccups, don't do anything if setting 
	// same frequency. 
	if (currFreq == freq) {
		return;
	}
	
	tc_stop(TC0, 0);
	if (freq == 0) {
		return;
	}
	
	// Find the best divisor for this frequency
	uint32_t ul_div, ul_tcclks;
	tc_find_mck_divisor(freq, SystemCoreClock, 
		&ul_div, &ul_tcclks, SystemCoreClock);
		
	// Put Timer into wavesel up RC mode with TIOA at 50% duty cycle
	// Clear TIOA at CPC match and set at CPA match
	tc_init(TC0, 0, ul_tcclks | TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_ACPC_CLEAR | TC_CMR_ACPA_SET);
	uint16_t rcVal = (SystemCoreClock / ul_div) / freq;
	tc_write_rc(TC0, 0, rcVal);
	tc_write_ra(TC0, 0, rcVal / 2);  // 50% duty cycle
	
	// Start the thing
	tc_start(TC0, 0);
	
	currFreq = freq;
}
Пример #2
0
static void enable_output(const channel_def_t* channel, int freq)
{
    if (channel->externally_driven)
    {
        uint32_t clock = sysclk_get_peripheral_bus_hz(channel->ex.timer) / 32; // clock source is PB / 32
        uint32_t rc = clock / freq;
            
        // check for over/underflow
        if (rc > 0xffff) rc = 0xffff;
        else if (rc < 8) rc = 8;

        // set up RA, RB, and RC.  always use 50% duty cycle (RA = RB = RC/2)
        tc_write_ra(channel->ex.timer, channel->ex.channel, (uint16_t)rc / 2);
        tc_write_rb(channel->ex.timer, channel->ex.channel, (uint16_t)rc / 2);
        tc_write_rc(channel->ex.timer, channel->ex.channel, (uint16_t)rc);
        tc_start(channel->ex.timer, channel->ex.channel);
    }
    else if (channel->in.active_level)
    {
        gpio_set_pin_high(channel->in.pin1);
    }
    else
    {
        gpio_set_pin_low(channel->in.pin1);
    }
}
Пример #3
0
/*! \brief  to load compare value in channel compare register
 */
void tmr_write_cmpreg(uint16_t compare_value)
{
#if SAM4E
    tc_write_ra(TIMER, TIMER_CHANNEL_ID, compare_value);
#else
    tc_write_rc(TIMER, TIMER_CHANNEL_ID, compare_value);
#endif
}
Пример #4
0
/**
 * \brief Configure Timer Counter 0 (TC0) to generate an interrupt every
 * second.
 */
static void demo_configure_tc0( void )
{
	/* Enable TC0 peripheral clock. */
	pmc_enable_periph_clk(ID_TC1);

	/* Configure TC for a 1s (= 1Hz) tick. */
	tc_init(TC0, 1, 0x4 | TC_CMR_ACPC_SET | TC_CMR_WAVE
			| TC_CMR_ACPA_CLEAR | TC_CMR_WAVSEL_UP_RC);

	/* 50% duty, 1s frequency */
	tc_write_ra(TC0, 1, 16384);
	tc_write_rc(TC0, 1, 32768);
}
Пример #5
0
void tc_init(void)
{
	  // The timer/counter instance and channel number are used in several functions.
	  // It's defined as local variable for ease-of-use causes and readability.
	  volatile avr32_tc_t *tc = WIFI_TC;

	  // Options for waveform genration.
	  tc_waveform_opt_t waveform_opt =
	  {
	    .channel  = WIFI_TC_CHANNEL_ID,        // Channel selection.

	    .bswtrg   = TC_EVT_EFFECT_NOOP,           // Software trigger effect on TIOB.
	    .beevt    = TC_EVT_EFFECT_NOOP,           // External event effect on TIOB.
	    .bcpc     = TC_EVT_EFFECT_NOOP,           // RC compare effect on TIOB.
	    .bcpb     = TC_EVT_EFFECT_NOOP,           // RB compare effect on TIOB.

	    .aswtrg   = TC_EVT_EFFECT_NOOP,           // Software trigger effect on TIOA.
	    .aeevt    = TC_EVT_EFFECT_NOOP,           // External event effect on TIOA.
	    .acpc     = TC_EVT_EFFECT_TOGGLE,         // RC compare effect on TIOA: toggle.
	    .acpa     = TC_EVT_EFFECT_TOGGLE,         // RA compare effect on TIOA: toggle (other possibilities are none, set and clear).

	    .wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,// Waveform selection: Up mode with automatic trigger(reset) on RC compare.
	    .enetrg   = FALSE,                        // External event trigger enable.
	    .eevt     = TC_EXT_EVENT_SEL_TIOB_INPUT,  // External event selection.
	    .eevtedg  = TC_SEL_NO_EDGE,               // External event edge selection.
	    .cpcdis   = FALSE,                        // Counter disable when RC compare.
	    .cpcstop  = FALSE,                        // Counter clock stopped with RC compare.

	    .burst    = TC_BURST_NOT_GATED,           // Burst signal selection.
	    .clki     = TC_CLOCK_RISING_EDGE,         // Clock inversion.
	    .tcclks   = TC_CLOCK_SOURCE_TC2           // Internal source clock 3, connected to fPBA / 2.
	  };

	  // Assign I/O to timer/counter channel pin & function.
	  gpio_enable_module_pin(WIFI_TC_CHANNEL_PIN, WIFI_TC_CHANNEL_FUNCTION);

	  // Initialize the timer/counter.
	  tc_init_waveform(tc, &waveform_opt);  // Initialize the timer/counter waveform.

	  // Set the compare triggers.
	  tc_write_ra(tc, WIFI_TC_CHANNEL_ID, 0x01A4);     // Set RA value.
	  tc_write_rc(tc, WIFI_TC_CHANNEL_ID, 0x0348);     // Set RC value.

	  // Start the timer/counter.
	  tc_start(tc, WIFI_TC_CHANNEL_ID);

}
Пример #6
0
/**
 * \brief TC configuration.
 */
static void dsp_configure_tc(void)
{
	pmc_enable_periph_clk(ID_TC1);

	/*
	 * Init timer counter 0
	 * RC Compare Effect on TIOA "SET"
	 * Waveform Mode is enabled
	 * UP mode with automatic trigger on RC Compare
	 */
	tc_init(TC0, 1,
			TC_CMR_ACPC_SET | TC_CMR_WAVE |
			TC_CMR_WAVSEL_UP_RC |TC_CMR_ACPA_CLEAR );

	/* Load in TC RA register */
	tc_write_ra(TC0, 1, TC_RA);
	/* Load in TC RC register */
	tc_write_rc(TC0, 1, TC_RC);
}
Пример #7
0
/**
 * \brief Configure TC TC_CHANNEL_WAVEFORM in waveform operating mode.
 */
static void tc_waveform_initialize(void)
{
	uint32_t ra, rc;

	/* Configure the PMC to enable the TC module. */
	sysclk_enable_peripheral_clock(ID_TC_WAVEFORM);

	/* Init TC to waveform mode. */
	tc_init(TC, TC_CHANNEL_WAVEFORM,
			/* Waveform Clock Selection */
			gc_waveconfig[gs_uc_configuration].ul_intclock
			| TC_CMR_WAVE /* Waveform mode is enabled */
			| TC_CMR_ACPA_SET /* RA Compare Effect: set */
			| TC_CMR_ACPC_CLEAR /* RC Compare Effect: clear */
			| TC_CMR_CPCTRG /* UP mode with automatic trigger on RC Compare */
			);

	/* Configure waveform frequency and duty cycle. */
#if (SAM4L)
	rc = (sysclk_get_peripheral_bus_hz(TC) /
			divisors[gc_waveconfig[gs_uc_configuration].ul_intclock]) /
			gc_waveconfig[gs_uc_configuration].us_frequency;
#else
	rc = (sysclk_get_peripheral_hz() /
			divisors[gc_waveconfig[gs_uc_configuration].ul_intclock]) /
			gc_waveconfig[gs_uc_configuration].us_frequency;
#endif
	tc_write_rc(TC, TC_CHANNEL_WAVEFORM, rc);
	ra = (100 - gc_waveconfig[gs_uc_configuration].us_dutycycle) * rc / 100;
	tc_write_ra(TC, TC_CHANNEL_WAVEFORM, ra);

	/* Enable TC TC_CHANNEL_WAVEFORM. */
	tc_start(TC, TC_CHANNEL_WAVEFORM);
	printf("Start waveform: Frequency = %d Hz,Duty Cycle = %2d%%\n\r",
			gc_waveconfig[gs_uc_configuration].us_frequency,
			gc_waveconfig[gs_uc_configuration].us_dutycycle);
}
Пример #8
0
/**
 * \name PWM functions
 * @{
 */
void ui_pwm_led_init(uint8_t lednum)
{
	/* Timer waveform options */
	static tc_waveform_opt_t waveform_options = {
		/* Channel selection. */
		.channel  = 1,

		.bswtrg   = TC_EVT_EFFECT_NOOP,
		.beevt    = TC_EVT_EFFECT_NOOP,
		.bcpc     = TC_EVT_EFFECT_NOOP,
		.bcpb     = TC_EVT_EFFECT_NOOP,

		.aswtrg   = TC_EVT_EFFECT_NOOP,
		.aeevt    = TC_EVT_EFFECT_NOOP,
		.acpc     = TC_EVT_EFFECT_NOOP,
		.acpa     = TC_EVT_EFFECT_NOOP,

		/* Waveform selection */
		.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
		/* External event trigger enable. */
		.enetrg   = false,
		/* External event selection (non-zero for Channel B to work) */
		.eevt     = !0,
		/* External event edge selection. */
		.eevtedg  = TC_SEL_NO_EDGE,

		.cpcdis   = false,
		.cpcstop  = false,

		.burst    = false,
		.clki     = false,
		/* Internal source clock 5, fPBA/128. */
		.tcclks   = TC_CLOCK_SOURCE_TC5,
	};
	switch (lednum) {
	case LED0:
		/* Assign output pin to timer/counter 0 channel A */

		/* Channel selection. */
		waveform_options.channel = 1;

		waveform_options.bcpc = TC_EVT_EFFECT_NOOP;

		waveform_options.bcpb = TC_EVT_EFFECT_NOOP;
		/* RC compare effect on TIOA. */
		waveform_options.acpc = TC_EVT_EFFECT_CLEAR;
		/* RA compare effect on TIOA. */
		waveform_options.acpa = TC_EVT_EFFECT_SET;

		/* Setup timer/counter waveform mode */
		sysclk_enable_peripheral_clock(&AVR32_TC0);
		tc_init_waveform(&AVR32_TC0, &waveform_options);

		/* Write the TOP (RC) and COMPARE (RA) values */
		tc_write_ra(&AVR32_TC0, 1, 1);   /* Set RA value. */
		tc_write_rc(&AVR32_TC0, 1, 255); /* Set RC value. */

		/* Start the timer PWM channel */
		tc_start(&AVR32_TC0, 1);
		break;

	case LED1:
		/* Assign output pin to timer/counter 1 channel B */

		/* Channel selection. */
		waveform_options.channel = 2;

		waveform_options.acpc = TC_EVT_EFFECT_NOOP;

		waveform_options.acpa = TC_EVT_EFFECT_NOOP;
		/* RC compare effect on TIOB. */
		waveform_options.bcpc = TC_EVT_EFFECT_CLEAR;
		/* RB compare effect on TIOB. */
		waveform_options.bcpb = TC_EVT_EFFECT_SET;

		/* Setup timer/counter waveform mode */
		sysclk_enable_peripheral_clock(&AVR32_TC1);
		tc_init_waveform(&AVR32_TC1, &waveform_options);

		/* Write the TOP (RC) and COMPARE (RB) values */
		tc_write_rb(&AVR32_TC1, 2, 1);   /* Set RB value. */
		tc_write_rc(&AVR32_TC1, 2, 255); /* Set RC value. */

		/* Start the timer PWM channel */
		tc_start(&AVR32_TC1, 2);
		break;

	default:
		break;
	}
}

void ui_pwm_update(uint8_t channum, uint8_t brightness)
{
	switch (channum) {
	case LED0:
		if (brightness != 0) {
			gpio_enable_module_pin(AVR32_TC0_A1_0_1_PIN,
					AVR32_TC0_A1_0_1_FUNCTION);
			tc_start(&AVR32_TC0, 1);
			tc_write_ra(&AVR32_TC0, 1, brightness);
		} else {
			tc_stop(&AVR32_TC0, 1);
			LED_Off(LED0);
		}

		break;

	case LED1:
		if (brightness != 0) {
			gpio_enable_module_pin(AVR32_TC1_B2_0_PIN,
					AVR32_TC1_B2_0_FUNCTION);
			tc_start(&AVR32_TC1, 2);
			tc_write_rb(&AVR32_TC1, 2, brightness);
		} else {
			tc_stop(&AVR32_TC1, 2);
			LED_Off(LED0);
		}

		break;

	default:
		break;
	}
}

/* End of PWM */
/** @} */

/**
 * \name Display functions
 * @{
 */

static void ui_display_enable(void)
{
	delay_init(sysclk_get_cpu_hz());

	et024006_Init( sysclk_get_cpu_hz(), sysclk_get_hsb_hz());

	/* Clear the display i.e. make it black */
	et024006_DrawFilledRect(0, 0, ET024006_WIDTH, ET024006_HEIGHT, BLACK );

	/* Set the backlight. */
	gpio_set_gpio_pin(ET024006DHU_BL_PIN);

	ui_display_init_rtc();

	ui_display_welcome_msg();
}
Пример #9
0
Файл: init.c Проект: mtwieg/NMR
static void tc_init_fast(volatile avr32_tc_t *tc)
{
	// Options for waveform generation.
	static const tc_waveform_opt_t waveform_opt_1 = {

		.channel  = FAST_TC_CHANNEL,  // Channel selection.
		.bswtrg   = TC_EVT_EFFECT_NOOP, // Software trigger effect on TIOB.
		.beevt    = TC_EVT_EFFECT_NOOP,	// External event effect on TIOB.
		.bcpc     = TC_EVT_EFFECT_NOOP,	// RC compare effect on TIOB.
		.bcpb     = TC_EVT_EFFECT_NOOP,	// RB compare effect on TIOB.
		.aswtrg   = TC_EVT_EFFECT_NOOP,	// Software trigger effect on TIOA.
		.aeevt    = TC_EVT_EFFECT_NOOP,	// External event effect on TIOA.
		.acpc     = TC_EVT_EFFECT_NOOP,	// RC compare effect on TIOA.
		.acpa     = TC_EVT_EFFECT_NOOP,	//RA compare effect on TIOA. 
		.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,	//Waveform selection: Up mode with automatic trigger(reset)
		.enetrg   = false,	//// External event trigger enable.
		.eevt     = 0,	//// External event selection.
		.eevtedg  = TC_SEL_NO_EDGE,	//// External event edge selection.
		.cpcdis   = false,	// Counter disable when RC compare.
		.cpcstop  = false,	// Counter clock stopped with RC compare.
		.burst    = false,	// Burst signal selection
		.clki     = false,	// Clock inversion.
		.tcclks   = TC_CLOCK_SOURCE_TC3	// Internal source clock 3, connected to fPBA / 8.
	};

	// Options for enabling TC interrupts
	static const tc_interrupt_t tc_interrupt = {
		.etrgs = 0,
		.ldrbs = 0,
		.ldras = 0,
		.cpcs  = 1, // Enable interrupt on RC compare alone
		.cpbs  = 0,
		.cpas  = 0,
		.lovrs = 0,
		.covfs = 0
	};
	// Initialize the timer/counter.
	tc_init_waveform(tc, &waveform_opt_1);

	tc_write_rc(tc, FAST_TC_CHANNEL, 10);
	// configure the timer interrupt
	tc_configure_interrupts(tc, FAST_TC_CHANNEL, &tc_interrupt);
}

static void tc_init_slow(volatile avr32_tc_t *tc)
{
	// Options for waveform generation.
	static const tc_waveform_opt_t waveform_opt_2 = {
		.channel  = SLOW_TC_fast_CHANNEL,	// Channel selection.
		.bswtrg   = TC_EVT_EFFECT_NOOP,	// Software trigger effect on TIOB.
		.beevt    = TC_EVT_EFFECT_NOOP,	// External event effect on TIOB.
		.bcpc     = TC_EVT_EFFECT_NOOP,	// RC compare effect on TIOB.
		.bcpb     = TC_EVT_EFFECT_NOOP,	// RB compare effect on TIOB.
		.aswtrg   = TC_EVT_EFFECT_NOOP,	// Software trigger effect on TIOA.
		.aeevt    = TC_EVT_EFFECT_NOOP,	// External event effect on TIOA.
		.acpc     = TC_EVT_EFFECT_CLEAR,	// RC compare effect on TIOA.
		.acpa     = TC_EVT_EFFECT_SET,	// RA compare effect on TIOA. 
		.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,	//Waveform selection: Up mode with automatic trigger(reset)
		.enetrg   = false,	// External event trigger enable.
		.eevt     = 0,	// External event selection.
		.eevtedg  = TC_SEL_NO_EDGE,	// External event edge selection.
		.cpcdis   = false,	// Counter disable when RC compare.
		.cpcstop  = false,	// Counter clock stopped with RC compare.
		.burst    = false,	// Burst signal selection.
		.clki     = false,	// Clock inversion.
		.tcclks   = TC_CLOCK_SOURCE_TC3	// Internal source clock 3, connected to fPBA / 8.
	};

	// Initialize the timer/counter.
	tc_init_waveform(tc, &waveform_opt_2);
	tc_write_rc(tc, SLOW_TC_fast_CHANNEL, 7500); //counter will count milliseconds
	tc_write_ra(tc, SLOW_TC_fast_CHANNEL, 3500); //configure ra so that TIOA0 is toggled
	
	static const tc_waveform_opt_t waveform_opt_3 = {
		.channel  = SLOW_TC_slow_CHANNEL,	// Channel selection.	
		.bswtrg   = TC_EVT_EFFECT_NOOP,	// Software trigger effect on TIOB.
		.beevt    = TC_EVT_EFFECT_NOOP,	// External event effect on TIOB.
		.bcpc     = TC_EVT_EFFECT_NOOP,	// RC compare effect on TIOB.
		.bcpb     = TC_EVT_EFFECT_NOOP,	// RB compare effect on TIOB.
		.aswtrg   = TC_EVT_EFFECT_NOOP,	// Software trigger effect on TIOA.
		.aeevt    = TC_EVT_EFFECT_NOOP,	// External event effect on TIOA.
		.acpc     = TC_EVT_EFFECT_NOOP,	// RC compare effect on TIOA.
		.acpa     = TC_EVT_EFFECT_NOOP,	//RA compare effect on TIOA. 
		.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,	//Waveform selection: Up mode with automatic trigger(reset)
		.enetrg   = false,	//// External event trigger enable.
		.eevt     = 0,	//// External event selection.
		.eevtedg  = TC_SEL_NO_EDGE,	//// External event edge selection.
		.cpcdis   = false,	// Counter disable when RC compare.
		.cpcstop  = false,	// Counter clock stopped with RC compare.
		.burst    = false,	// Burst signal selection.
		.clki     = false,	// Clock inversion.
		.tcclks   = TC_CLOCK_SOURCE_XC0	// Use XC1 as clock source.  Must configure TIOA0 to be XC1
	};
	
	tc_init_waveform(tc, &waveform_opt_3);
	tc_write_rc(tc, SLOW_TC_slow_CHANNEL, 100); //
	tc_select_external_clock(tc,SLOW_TC_slow_CHANNEL,AVR32_TC_BMR_TC0XC0S_TIOA1); //use TIOA1 as XC0
}


	static void configure_hmatrix(uint32_t mode)
{
	// Configure all Slave in Last Default Master
#if (defined AVR32_HMATRIX) 
	for(uint32_t i = 0; i < AVR32_HMATRIX_SLAVE_NUM; i++) {
		AVR32_HMATRIX.SCFG[i].defmstr_type = mode;
	}
#endif
#if (defined AVR32_HMATRIXB)
	for(uint32_t i = 0;i < AVR32_HMATRIXB_SLAVE_NUM; i++) {
		AVR32_HMATRIXB.SCFG[i].defmstr_type = mode;
	}
#endif 
}

void board_init(void)
{
	/* This function is meant to contain board-specific initialization code
	 * for, e.g., the I/O pins. The initialization can rely on application-
	 * specific board configuration, found in conf_board.h.
	 */
	gpio_local_init();
	
	static pcl_freq_param_t pcl_freq_param =
{
	.cpu_f        = CPU_SPEED,
	.pba_f        = PBA_SPEED,
	.osc0_f       = FOSC0,
	.osc0_startup = OSC0_STARTUP
};

	if (pcl_configure_clocks(&pcl_freq_param) != PASS)
	while (true);
	
	configure_hmatrix(AVR32_HMATRIXB_DEFMSTR_TYPE_NO_DEFAULT);
	
	AVR32_LowLevelInit();
	
	//configure all GPIO
	gpio_local_enable_pin_output_driver(ADC_CONV_pin);
	gpio_local_clr_gpio_pin(ADC_CONV_pin);
	gpio_local_enable_pin_output_driver(DDS_IOUD_pin);
	gpio_local_clr_gpio_pin(DDS_IOUD_pin);
	gpio_local_enable_pin_output_driver(DDS_RESET_pin);
	gpio_local_clr_gpio_pin(DDS_RESET_pin);
	gpio_local_enable_pin_output_driver(DDS_PDN_pin);
	gpio_local_set_gpio_pin(DDS_PDN_pin);
	
	gpio_local_enable_pin_output_driver(DDS_P0_pin);
	gpio_local_clr_gpio_pin(DDS_P0_pin);
	gpio_local_enable_pin_output_driver(DDS_P1_pin);
	gpio_local_clr_gpio_pin(DDS_P1_pin);
	gpio_local_enable_pin_output_driver(DDS_P2_pin);
	gpio_local_clr_gpio_pin(DDS_P2_pin);
	gpio_local_enable_pin_output_driver(DDS_P3_pin);
	gpio_local_clr_gpio_pin(DDS_P3_pin);
	
	gpio_local_enable_pin_output_driver(RXSW_pin);
	gpio_local_clr_gpio_pin(RXSW_pin);
	gpio_local_enable_pin_output_driver(TXSW_pin);
	gpio_local_clr_gpio_pin(TXSW_pin);
	gpio_local_enable_pin_output_driver(TPAbias_pin);
	gpio_local_clr_gpio_pin(TPAbias_pin);
	gpio_local_enable_pin_output_driver(GEN1_pin);
	gpio_local_clr_gpio_pin(GEN1_pin);
	gpio_local_enable_pin_output_driver(GEN2_pin);
	gpio_local_clr_gpio_pin(GEN2_pin);
	
	gpio_local_enable_pin_output_driver(PWM0_pin);
	gpio_local_clr_gpio_pin(PWM0_pin);
	
	gpio_local_disable_pin_output_driver(SD_detect_pin);
	
	//configure all peripheral IO
	
	static const gpio_map_t GCLK_GPIO_MAP =
	{
		{AVR32_SCIF_GCLK_0_1_PIN, AVR32_SCIF_GCLK_0_1_FUNCTION}
	};
	
	gpio_enable_module(GCLK_GPIO_MAP,
			sizeof(GCLK_GPIO_MAP) / sizeof(GCLK_GPIO_MAP[0]));
	
	genclk_enable_config(9, GENCLK_SRC_CLK_CPU, 2);
	
	static const gpio_map_t SPI_GPIO_MAP =
	{
		{SPI1_SCK_PIN, SPI1_SCK_FUNCTION},
		{SPI1_MOSI_PIN, SPI1_MOSI_FUNCTION},
		{SPI1_MISO_PIN, SPI1_MISO_FUNCTION},
		{SPI1_NPCS2_PIN, SPI1_NPCS2_FUNCTION}
	};
	
	gpio_enable_module(SPI_GPIO_MAP,
			sizeof(SPI_GPIO_MAP) / sizeof(SPI_GPIO_MAP[0]));


spi_options_t SPI1_OPTIONS_0 = 
{
  .reg			= 0,		//! The SPI channel to set up.
  .baudrate		= 30000000,	//! Preferred baudrate for the SPI.
  .bits			=16,	//! Number of bits in each character (8 to 16).
  .spck_delay	=0,	//! Delay before first clock pulse after selecting slave (in PBA clock periods). 
  .trans_delay	=0,	//! Delay between each transfer/character (in PBA clock periods).
  .stay_act		=0,	 //! Sets this chip to stay active after last transfer to it.
  .spi_mode		=1,	//! Which SPI mode to use when transmitting.
  .modfdis		=1	 //! Disables the mode fault detection.
};

spi_options_t SPI1_OPTIONS_3 = 
{
  .reg			= 3,		//! The SPI channel to set up.
  .baudrate		= 30000000,	//! Preferred baudrate for the SPI.
  .bits			=8,	//! Number of bits in each character (8 to 16).
  .spck_delay	=0,	//! Delay before first clock pulse after selecting slave (in PBA clock periods).
  .trans_delay	=0,	//! Delay between each transfer/character (in PBA clock periods).
  .stay_act		=1,	//! Sets this chip to stay active after last transfer to it.
  .spi_mode		=0,	//! Which SPI mode to use when transmitting.
  .modfdis		=1	//! Disables the mode fault detection.
};

	spi_initMaster(SPI1, &SPI1_OPTIONS_0); 
	spi_selectionMode(SPI1,1,0,0);
	spi_enable(SPI1);
	spi_setupChipReg(SPI1,&SPI1_OPTIONS_0,PBA_SPEED);
	spi_setupChipReg(SPI1,&SPI1_OPTIONS_3,PBA_SPEED);
	spi_selectChip(SPI1, 3);
	
	static const gpio_map_t USB_USART_GPIO_MAP =
	{
		{USB_USART_RX_PIN, USB_USART_RX_FUNCTION},
		{USB_USART_TX_PIN, USB_USART_TX_FUNCTION},
		{USB_USART_RTS_PIN, USB_USART_RTS_FUNCTION},
		{USB_USART_CTS_PIN, USB_USART_CTS_FUNCTION}
	};
	
	gpio_enable_module(USB_USART_GPIO_MAP,
			sizeof(USB_USART_GPIO_MAP) / sizeof(USB_USART_GPIO_MAP[0]));
			
	static const usart_options_t USB_USART_OPTIONS =
	{
		.baudrate     = 3000000,
		.charlength   = 8,
		.paritytype   = USART_NO_PARITY,
		.stopbits     = USART_1_STOPBIT,
		.channelmode  = USART_NORMAL_CHMODE
	};
			
	usart_init_hw_handshaking(USB_USART, &USB_USART_OPTIONS, PBA_SPEED);
	
	static const gpio_map_t LCD_USART_GPIO_MAP =
	{
		{LCD_USART_RX_PIN, LCD_USART_RX_FUNCTION},
		{LCD_USART_TX_PIN, LCD_USART_TX_FUNCTION}
	};
	
	gpio_enable_module(LCD_USART_GPIO_MAP,
			sizeof(LCD_USART_GPIO_MAP) / sizeof(LCD_USART_GPIO_MAP[0]));
			
	static const usart_options_t LCD_USART_OPTIONS =
	{
		.baudrate     = 115200,
		.charlength   = 8,
		.paritytype   = USART_NO_PARITY,
		.stopbits     = USART_1_STOPBIT,
		.channelmode  = USART_NORMAL_CHMODE
	};
			
	usart_init_rs232(LCD_USART, &LCD_USART_OPTIONS, PBA_SPEED);
	LCD_USART->cr|=AVR32_USART_CR_STTTO_MASK; //set timeout to stop until new character is received
	LCD_USART->rtor=230;	//set to timeout in 2ms
	
	
	my_pdca_init_channel(LCD_USART_RX_PDCA_CHANNEL, (uint32_t)(&LCD_USART_buffer),(uint32_t)(sizeof(LCD_USART_buffer)),LCD_USART_RX_PDCA_PID,0,0, PDCA_TRANSFER_SIZE_BYTE);
	pdca_disable(LCD_USART_RX_PDCA_CHANNEL);
	
	my_pdca_init_channel(USB_USART_RX_PDCA_CHANNEL, (uint32_t)(&host_USART_buffer),(uint32_t)(sizeof(host_USART_buffer)),USB_USART_RX_PDCA_PID,0,0, PDCA_TRANSFER_SIZE_BYTE);
	pdca_disable(USB_USART_RX_PDCA_CHANNEL);
	
	USB_USART->cr|=AVR32_USART_CR_STTTO_MASK; //set timeout to stop until new character is received
	USB_USART->rtor=15000;	//set to timeout in 1ms
	
	// GPIO pins used for SD/MMC interface
  static const gpio_map_t SD_MMC_SPI_GPIO_MAP =
  {
    {SPI0_SCK_PIN,  SPI0_SCK_FUNCTION },  // SPI Clock.
    {SPI0_MISO_PIN, SPI0_MISO_FUNCTION},  // MISO.
    {SPI0_MOSI_PIN, SPI0_MOSI_FUNCTION},  // MOSI.
    {SPI0_NPCS0_PIN, SPI0_NPCS0_FUNCTION}   // Chip Select NPCS.
  };

   //SPI options.
  spi_options_t SD_spiOptions =
  {
    .reg          = SD_MMC_SPI_NPCS,
    .baudrate     = SD_SPI_SPEED,  // Defined in conf_sd_mmc_spi.h.
    .bits         = 8,          // Defined in conf_sd_mmc_spi.h.
    .spck_delay   = 0,
    .trans_delay  = 0,
    .stay_act     = 1,
    .spi_mode     = 0,
    .modfdis      = 1
  };

  // Assign I/Os to SPI.
  gpio_enable_module(SD_MMC_SPI_GPIO_MAP,sizeof(SD_MMC_SPI_GPIO_MAP) / sizeof(SD_MMC_SPI_GPIO_MAP[0]));
  // Initialize as master.
  spi_initMaster(SPI0, &SD_spiOptions);
  // Set SPI selection mode: variable_ps, pcs_decode, delay.
  spi_selectionMode(SPI0, 0, 0, 0);
  // Enable SPI module.
  spi_enable(SPI0);
  // Initialize SD/MMC driver with SPI clock (PBA).
  sd_mmc_spi_init(SD_spiOptions, PBA_SPEED);
  
  tc_init_fast(FAST_TC);
  tc_init_slow(SLOW_TC);
  
  static const gpio_map_t DACIFB_GPIO_MAP =
  {
    {AVR32_DACREF_PIN,AVR32_DACREF_FUNCTION},
    {AVR32_ADCREFP_PIN,AVR32_ADCREFP_FUNCTION},
    {AVR32_ADCREFN_PIN,AVR32_ADCREFN_FUNCTION},
    {DAC0A_pin, DAC0A_FUNCTION},
	{DAC1A_pin, DAC1A_FUNCTION}
  };
  
  gpio_enable_module(DACIFB_GPIO_MAP, sizeof(DACIFB_GPIO_MAP) / sizeof(DACIFB_GPIO_MAP[0]));
  
  dacifb_opt_t dacifb_opt = {
    .reference                  = DACIFB_REFERENCE_EXT ,        // VDDANA Reference
    .channel_selection          = DACIFB_CHANNEL_SELECTION_A,     // Selection Channels A&B
    .low_power                  = false,                          // Low Power Mode
    .dual                       = false,                          // Dual Mode
    .prescaler_clock_hz         = DAC_PRESCALER_CLK     // Prescaler Clock (Should be 500Khz)
};

// DAC Channel Configuration
dacifb_channel_opt_t dacifb_channel_opt = {
    .auto_refresh_mode    = true,                      // Auto Refresh Mode
    .trigger_mode         = DACIFB_TRIGGER_MODE_MANUAL, // Trigger selection
    .left_adjustment      = false,                      // Right Adjustment
    .data_shift           = 0,                          // Number of Data Shift
    .data_round_enable    = false                       // Data Rouding Mode                                              };
};

volatile avr32_dacifb_t *dacifb0 = &AVR32_DACIFB0; // DACIFB IP registers address
volatile avr32_dacifb_t *dacifb1 = &AVR32_DACIFB1; // DACIFB IP registers address

//The factory calibration for DADIFB is broken, so use manual calibration
//dacifb_get_calibration_data(DAC0,&dacifb_opt,0);

dacifb_opt.gain_calibration_value=0x0090;
dacifb_opt.offset_calibration_value=0x0153;

  // configure DACIFB0
dacifb_configure(DAC0,&dacifb_opt,PBA_SPEED);

dacifb_configure_channel(DAC0,DACIFB_CHANNEL_SELECTION_A,&dacifb_channel_opt,DAC_PRESCALER_CLK);

dacifb_start_channel(DAC0,DACIFB_CHANNEL_SELECTION_A,PBA_SPEED);

//The factory calibration for DADIFB is broken, so use manual calibration					
dacifb_set_value(DAC0,DACIFB_CHANNEL_SELECTION_A,false,1024);					   
					   				 
//dacifb_get_calibration_data(DAC1, &dacifb_opt,1);
							
dacifb_opt.gain_calibration_value=0x0084;
dacifb_opt.offset_calibration_value=0x0102;							

  // configure DACIFB1
dacifb_configure(DAC1,&dacifb_opt,PBA_SPEED);
				   
dacifb_configure_channel(DAC1,DACIFB_CHANNEL_SELECTION_A,&dacifb_channel_opt,DAC_PRESCALER_CLK);

dacifb_start_channel(DAC1,DACIFB_CHANNEL_SELECTION_A,PBA_SPEED);
					   
dacifb_set_value(DAC1,DACIFB_CHANNEL_SELECTION_A,false,1024);					   				   				 

DAC0->dr0=2048;
DAC1->dr0=4095;
}
Пример #10
0
void PWM_timer_init(void)
{
	//MUST CHANGE BACK!!!!!
	collective = 100;
	yaw = 0;
	pitch = 0;
	roll = 0;
	t_a = 0;
	t_b = 0;
	t_c = 0;
	t_r = 0;
	
	//Set up the GPIO pins for output of the timers
	gpio_enable_module_pin(AVR32_TC1_A2_0_PIN, AVR32_TC1_A2_0_FUNCTION);	
	gpio_enable_module_pin(AVR32_TC1_B0_0_PIN, AVR32_TC1_B0_0_FUNCTION);
	gpio_enable_module_pin(AVR32_TC1_B1_0_PIN, AVR32_TC1_B1_0_FUNCTION);
	gpio_enable_module_pin(AVR32_TC0_B2_0_PIN, AVR32_TC0_B2_0_FUNCTION);
	gpio_enable_module_pin(AVR32_TC0_B0_0_0_PIN, AVR32_TC0_B0_0_0_FUNCTION);
	
			
	// Timer waveform options
	const tc_waveform_opt_t waveform_options_b0_1 = {
	//! Channel selection.
	.channel  = 0,
	
	//! Software trigger effect on TIOB.
	.bswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOB.
	.beevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOB.
	.bcpc     = TC_EVT_EFFECT_CLEAR,
	//! RB compare effect on TIOB.
	.bcpb     = TC_EVT_EFFECT_SET,
	
	//! Software trigger effect on TIOA.
	.aswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOA.
	.aeevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOA.
	.acpc     = TC_EVT_EFFECT_NOOP,
	//! RA compare effect on TIOA.
	.acpa     = TC_EVT_EFFECT_NOOP,
	
	//! Waveform selection
	.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
	//! External event trigger enable.
	.enetrg   = false,
	//! External event selection (non-zero for Channel B to work)
	.eevt     = !0,
	//! External event edge selection.
	.eevtedg  = TC_SEL_NO_EDGE,
	//! Counter disable when RC compare.
	.cpcdis   = false,
	//! Counter clock stopped with RC compare.
	.cpcstop  = false,
	
	//! Burst signal selection.
	.burst    = false,
	//! Clock inversion selection.
	.clki     = false,
	//! Internal source clock 5, fPBA/128.
	.tcclks   = TC_CLOCK_SOURCE_TC4,
	};
	
	const tc_waveform_opt_t waveform_options_b0_0 = {
	//! Channel selection.
	.channel  = 0,
	
	//! Software trigger effect on TIOB.
	.bswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOB.
	.beevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOB.
	.bcpc     = TC_EVT_EFFECT_CLEAR,
	//! RB compare effect on TIOB.
	.bcpb     = TC_EVT_EFFECT_SET,
	
	//! Software trigger effect on TIOA.
	.aswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOA.
	.aeevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOA.
	.acpc     = TC_EVT_EFFECT_NOOP,
	//! RA compare effect on TIOA.
	.acpa     = TC_EVT_EFFECT_NOOP,
	
	//! Waveform selection
	.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
	//! External event trigger enable.
	.enetrg   = false,
	//! External event selection (non-zero for Channel B to work)
	.eevt     = !0,
	//! External event edge selection.
	.eevtedg  = TC_SEL_NO_EDGE,
	//! Counter disable when RC compare.
	.cpcdis   = false,
	//! Counter clock stopped with RC compare.
	.cpcstop  = false,
	
	//! Burst signal selection.
	.burst    = false,
	//! Clock inversion selection.
	.clki     = false,
	//! Internal source clock 5, fPBA/128.
	.tcclks   = TC_CLOCK_SOURCE_TC4,
	};	
	
	const tc_waveform_opt_t waveform_options_b1 = {
	//! Channel selection.
	.channel  = 1,
	
	//! Software trigger effect on TIOB.
	.bswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOB.
	.beevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOB.
	.bcpc     = TC_EVT_EFFECT_CLEAR,
	//! RB compare effect on TIOB.
	.bcpb     = TC_EVT_EFFECT_SET,
	
	//! Software trigger effect on TIOA.
	.aswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOA.
	.aeevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOA.
	.acpc     = TC_EVT_EFFECT_NOOP,
	//! RA compare effect on TIOA.
	.acpa     = TC_EVT_EFFECT_NOOP,
	
	//! Waveform selection
	.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
	//! External event trigger enable.
	.enetrg   = false,
	//! External event selection (non-zero for Channel B to work)
	.eevt     = !0,
	//! External event edge selection.
	.eevtedg  = TC_SEL_NO_EDGE,
	//! Counter disable when RC compare.
	.cpcdis   = false,
	//! Counter clock stopped with RC compare.
	.cpcstop  = false,
	
	//! Burst signal selection.
	.burst    = false,
	//! Clock inversion selection.
	.clki     = false,
	//! Internal source clock 5, fPBA/128.
	.tcclks   = TC_CLOCK_SOURCE_TC4,
	};	
	
	const tc_waveform_opt_t waveform_options_b2 = {
	//! Channel selection.
	.channel  = 2,
	
	//! Software trigger effect on TIOB.
	.bswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOB.
	.beevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOB.
	.bcpc     = TC_EVT_EFFECT_CLEAR,
	//! RB compare effect on TIOB.
	.bcpb     = TC_EVT_EFFECT_SET,
	
	//! Software trigger effect on TIOA.
	.aswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOA.
	.aeevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOA.
	.acpc     = TC_EVT_EFFECT_CLEAR,
	//! RA compare effect on TIOA.
	.acpa     = TC_EVT_EFFECT_SET,
	
	//! Waveform selection
	.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
	//! External event trigger enable.
	.enetrg   = false,
	//! External event selection (non-zero for Channel B to work)
	.eevt     = !0,
	//! External event edge selection.
	.eevtedg  = TC_SEL_NO_EDGE,
	//! Counter disable when RC compare.
	.cpcdis   = false,
	//! Counter clock stopped with RC compare.
	.cpcstop  = false,
	
	//! Burst signal selection.
	.burst    = false,
	//! Clock inversion selection.
	.clki     = false,
	//! Internal source clock 5, fPBA/128.
	.tcclks   = TC_CLOCK_SOURCE_TC4,
	};	
	
	const tc_waveform_opt_t waveform_options_a2 = {
	//! Channel selection.
	.channel  = 2,
	
	//! Software trigger effect on TIOB.
	.bswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOB.
	.beevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOB.
	.bcpc     = TC_EVT_EFFECT_NOOP,
	//! RB compare effect on TIOB.
	.bcpb     = TC_EVT_EFFECT_NOOP,
	
	//! Software trigger effect on TIOA.
	.aswtrg   = TC_EVT_EFFECT_NOOP,
	//! External event effect on TIOA.
	.aeevt    = TC_EVT_EFFECT_NOOP,
	//! RC compare effect on TIOA.
	.acpc     = TC_EVT_EFFECT_CLEAR,
	//! RA compare effect on TIOA.
	.acpa     = TC_EVT_EFFECT_SET,
	
	//! Waveform selection
	.wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
	//! External event trigger enable.
	.enetrg   = false,
	//! External event selection (non-zero for Channel B to work)
	.eevt     = !0,
	//! External event edge selection.
	.eevtedg  = TC_SEL_NO_EDGE,
	//! Counter disable when RC compare.
	.cpcdis   = false,
	//! Counter clock stopped with RC compare.
	.cpcstop  = false,
	
	//! Burst signal selection.
	.burst    = false,
	//! Clock inversion selection.
	.clki     = false,
	//! Internal source clock 5, fPBA/128.
	.tcclks   = TC_CLOCK_SOURCE_TC4,
	};	

	// Setup timer/counter waveform mode
	sysclk_enable_peripheral_clock(&AVR32_TC0);
	sysclk_enable_peripheral_clock(&AVR32_TC1);
	tc_init_waveform(&AVR32_TC1, &waveform_options_b1);
	tc_init_waveform(&AVR32_TC1, &waveform_options_b0_1);
	tc_init_waveform(&AVR32_TC1, &waveform_options_a2);
	tc_init_waveform(&AVR32_TC0, &waveform_options_b0_0);
	tc_init_waveform(&AVR32_TC0, &waveform_options_b2);
	
	
	tc_write_rb(&AVR32_TC1, 0, B_BASE);  
	tc_write_rc(&AVR32_TC1, 0, RC_VAL); 
	tc_write_rb(&AVR32_TC1, 1, R_BASE);   
	tc_write_rc(&AVR32_TC1, 1, RC_VAL); 
	tc_write_ra(&AVR32_TC1, 2, A_BASE);
	tc_write_rc(&AVR32_TC1, 2, RC_VAL); 
	
	tc_write_rb(&AVR32_TC0, 0, M_BASE);   
	tc_write_rc(&AVR32_TC0, 0, RC_VAL); 
	tc_write_rb(&AVR32_TC0, 2, C_BASE);   
	tc_write_rc(&AVR32_TC0, 2, RC_VAL); 
	
	// Start the timer PWM channels
	tc_start(&AVR32_TC1, 2);
	tc_start(&AVR32_TC1, 0);
	tc_start(&AVR32_TC1, 1);
	tc_start(&AVR32_TC0, 0);
	tc_start(&AVR32_TC0, 2);	
}

void PWM_tester(char servo, int delay){	
	int initial_delay = 2000;
	if(servo=='a'){
		for(int i=0;i<=O_MAX;i++){
			tc_write_ra(&AVR32_TC1, 2, A_BASE-i);
			if(i==0) delay_ms(initial_delay);
			else delay_ms(delay);
		}
	}
	else if(servo=='b'){
		for(int i=0;i<=O_MAX;i++){
			tc_write_rb(&AVR32_TC1, 0, B_BASE+i);
			if(i==0) delay_ms(initial_delay);
			else delay_ms(delay);
		}
	}
	else if(servo=='c'){
		for(int i=0;i<=O_MAX;i++){
			tc_write_rb(&AVR32_TC0, 2, C_BASE-i);
			if(i==0) delay_ms(initial_delay);
			else delay_ms(delay);
		}
	}
	else if(servo=='r'){
		for(int i=0;i<=R_MAX;i++){
			tc_write_rb(&AVR32_TC1, 1, R_BASE+i);
			if(i==0) delay_ms(initial_delay);
			else delay_ms(delay);
		}
	}
	else if(servo=='e'){
		for(int i=0;i<O_MAX;i++){
			tc_write_ra(&AVR32_TC1, 2, A_BASE-i);
			tc_write_rb(&AVR32_TC1, 0, B_BASE+i);
			tc_write_rb(&AVR32_TC0, 2, C_BASE-i);
			if(i<R_MAX)	tc_write_rb(&AVR32_TC1, 1, R_BASE+i);
			
			//tc_write_rb(&AVR32_TC0, 0, 255);
			if(i==0) delay_ms(3000);
			else delay_ms(delay);
		}
	}
}

void PWM_update(void){
	//gpio_toggle_pin(LED1_GPIO);	
	t_a = collective-pitch+roll;
	t_b = collective-pitch-roll;
	t_c = collective+pitch+pitch;
	t_r = yaw+100;
	
	//if(collective!=0 || yaw !=0 || pitch!=0 || roll !=0) gpio_toggle_pin(LED0_GPIO);
	check_max_values();

	tc_write_ra(&AVR32_TC1, 2, A_BASE-t_a);
	tc_write_rb(&AVR32_TC1, 0, B_BASE+t_b);
	tc_write_rb(&AVR32_TC0, 2, C_BASE-t_c);
	tc_write_rb(&AVR32_TC1, 1, R_BASE+t_r);
}	

void set_motor(char setting){
	int level = (int) setting;
	if(level>100) level = 100;
	level = (int)(level * 3.75f);
	tc_write_rb(&AVR32_TC0, 0, M_BASE - level);
	motor = level;
}

int get_servo_dat(char servo){
	switch(servo){
	case 'a':
		return t_a;
		break;
	case 'b':
		return t_b;
		break;
	case 'c':
		return t_c;
		break;
	case 'r':
		return t_r;
		break;
	case 'o':
		return collective;
		break;
	case 'y':
		return yaw;
		break;
	case 'p':
		return pitch;
		break;
	case 'l':
		return roll;
		break;
	case 'm':
		return motor;
		break;
	default:
		return 0;
		break;
	}
}

void check_max_values(void){
	if(t_a>=O_MAX)   t_a = O_MAX;
	else if(t_a<0) t_a = 0;
	if(t_b>=O_MAX)   t_b = O_MAX;
	else if(t_b<0) t_b = 0;
	if(t_c>=O_MAX)   t_c = O_MAX;
	else if(t_c<0) t_c = 0;
	if(t_r>=R_MAX)   t_r = R_MAX;
	else if(t_r<0) t_r = 0;
}

void set_PWM_dat(int16_t* PWM_dat, char where){
	/*
	[0] = packet type
	[1] = collective
	[2] = yaw
	[3] = pitch
	[4] = roll
	*/
	//gpio_toggle_pin(LED2_GPIO);
	switch (where){
		case 'm': 
			collective	= (int8_t)PWM_dat[1];
			yaw			= (int8_t)PWM_dat[2];
			pitch		= (int8_t)PWM_dat[3];
			roll		= (int8_t)PWM_dat[4];
			break;
		default:
			collective	= PWM_dat[0];
			yaw			= PWM_dat[1];
			pitch		= PWM_dat[2];
			roll		= PWM_dat[3];
			break;
	}
	check_orientation_values();
}

void check_orientation_values(void){
	if(pitch>MAX_PITCH)       pitch = MAX_PITCH;
	else if(pitch<-MAX_PITCH) pitch = -MAX_PITCH;
	if(roll>MAX_ROLL)       roll = MAX_ROLL;
	else if(roll<-MAX_ROLL) roll = -MAX_ROLL;
	if(yaw>MAX_YAW)       yaw = MAX_YAW;
	else if(yaw<-MAX_YAW) yaw = -MAX_YAW;
}
Пример #11
0
static void configure_time_trigger_for_ssc(uint32_t ssc_trigger_hz)
{
	
#if 0
	gpio_configure_pin(PIO_PA12_IDX, PIO_PERIPH_B);
	pmc_enable_periph_clk(ID_PWM);

	/* Disable PWM channels */
	pwm_channel_disable(PWM, PWM_CHANNEL_1);

	/* Set PWM clock A as PWM_FREQUENCY*PERIOD_VALUE (clock B is not used) */
	pwm_clock_t clock_setting = {
		.ul_clka = 1000 * 100,
		.ul_clkb = 0,
		.ul_mck = sysclk_get_cpu_hz()
	};
	pwm_init(PWM, &clock_setting);
	
	pwm_channel_t g_pwm_channel;

	/* Period is left-aligned */
	g_pwm_channel.alignment = PWM_ALIGN_LEFT;
	/* Output waveform starts at a low level */
	g_pwm_channel.polarity = PWM_LOW;
	/* Use PWM clock A as source clock */
	g_pwm_channel.ul_prescaler = PWM_CMR_CPRE_CLKA;
	/* Period value of output waveform */
	g_pwm_channel.ul_period = 100;
	/* Duty cycle value of output waveform */
	g_pwm_channel.ul_duty = 50;
	g_pwm_channel.channel = PWM_CHANNEL_1;
	pwm_channel_init(PWM, &g_pwm_channel);
	
	/* Disable channel counter event interrupt */
	pwm_channel_disable_interrupt(PWM, PWM_CHANNEL_1, 0);
	
	pwm_channel_enable(PWM, PWM_CHANNEL_1);
#endif


	
	uint32_t ul_div = 0;
	uint32_t ul_tc_clks = 0;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();

	pmc_set_writeprotect(false);

	// Enable peripheral clock.
	pmc_enable_periph_clk(CONF_SSC_CLOCK_SOURCE_ID);

	// TIOA configuration 
	// gpio_configure_pin(PIN_TC0_TIOA0, PIN_TC0_TIOA0_FLAGS);
	// tc_set_writeprotect(TC2, true);
	tc_set_writeprotect(CONF_SSC_CLOCK_TC, false);

	// Configure TC for a 1Hz frequency and trigger on RC compare.
	tc_find_mck_divisor(ssc_trigger_hz, ul_sysclk, &ul_div, &ul_tc_clks, ul_sysclk);
	tc_init(CONF_SSC_CLOCK_TC, CONF_SSC_CLOCK_CHANNEL, ul_tc_clks | TC_CMR_WAVSEL_UP_RC | TC_CMR_WAVE | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);
	uint32_t tmp_val = (ul_sysclk / ul_div) / ssc_trigger_hz;
	
	tc_write_ra(CONF_SSC_CLOCK_TC, CONF_SSC_CLOCK_CHANNEL, tmp_val / 2);
	tc_write_rc(CONF_SSC_CLOCK_TC, CONF_SSC_CLOCK_CHANNEL, tmp_val);

	// Start the Timer.
	tc_start(CONF_SSC_CLOCK_TC, CONF_SSC_CLOCK_CHANNEL);

}

void tm_stick_init(uint32_t bus_speed_hz) {
	if(g_tm_stick_data.mutex == NULL) {
		g_tm_stick_data.mutex =  xSemaphoreCreateMutex();
	}
	
	if(g_tm_stick_data.rtos_task_semaphore == NULL) {
		vSemaphoreCreateBinary(g_tm_stick_data.rtos_task_semaphore);
	}
	
	configure_time_trigger_for_ssc(1000);
	
	sysclk_enable_peripheral_clock(ID_SSC);
	ssc_reset(SSC);
	// Do not go over 1MHz, the pulse will be too long and extend over to the next clock's rising edge (The spec. sheet of 4021BCM does not really list the operation times of 3.3V operation.
	// I tested a couple of speeds.... at 1.25MHz, I found that it sometimes misses some pulses.
	if(bus_speed_hz > TM_STICK_MAX_BUS_SPEED){
		bus_speed_hz = TM_STICK_MAX_BUS_SPEED;
	}
	ssc_set_clock_divider(SSC, bus_speed_hz, sysclk_get_cpu_hz()); 
	clock_opt_t rx_clk_opt = {
		.ul_cks = SSC_RCMR_CKS_MCK,
		.ul_cko = SSC_RCMR_CKO_TRANSFER,
// TODO: Fix the SSC clock for some reason shift 1/2 clock pulse position.
// This makes the button results shift one position to the right. So we have to change rising/falling edge to "correct" it (oh, well, "hack" around it).
// Don't know why.
// One possible patch up is to use a pin to signal which one is desired to determine which of the following settings to use..
#if defined(CONF_BOARD_ARDUINO_DUE) 
		.ul_cki = 0, //SSC_RCMR_CKI,
#else
		.ul_cki = SSC_RCMR_CKI,
#endif
		.ul_ckg = SSC_RCMR_CKG_CONTINUOUS,
		.ul_start_sel = SSC_RCMR_START_RF_FALLING,
		.ul_period = 0,
		.ul_sttdly = 0
	};
	
	data_frame_opt_t rx_data_frame_opt = {
		.ul_datlen = 23,
		.ul_msbf = 0,  //SSC_RFMR_MSBF,
		.ul_fsos = SSC_RFMR_FSOS_NONE,
		.ul_datnb = 0,
		.ul_fsedge = SSC_RFMR_FSEDGE_NEGATIVE,
		.ul_fslen = 0,
		.ul_fslen_ext = 0
	};
	
	ssc_set_receiver(SSC, &rx_clk_opt, &rx_data_frame_opt);
	ssc_enable_interrupt(SSC, SSC_IER_RXRDY);
	
	// It is VERY IMPORTANT to set the priority of the interrupt to conform to what FreeRTOS needs because we are calling FreeRTOS interrupt-safe APIs (those *FromISR) from within interrupt handlers.
	// If we don't do this, if would work at the beginning, and then eventually the whole thing will come crashing down.
	// And it's not gonna crash even after millions of interrupts are handled. It will come crashing down in some very weird place after you start using another interrupt handler, like the pio handlers, and only after some handlling...
	// And, it will appear random. You press the button a couple of times, it dies. Then, at other times, you press and hold the button, etc. etc. Each time will be different.
	// You would be suspecting your stack overflowed, your code does a wild pointer, etc. etc. It's very difficult to debug. Trust me, you don't wanna go there.
	NVIC_ClearPendingIRQ(SSC_IRQn);
	NVIC_SetPriority(SSC_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
	
	NVIC_EnableIRQ(SSC_IRQn); 
	
	ssc_enable_rx(SSC);
}

void SSC_Handler( void ) {	
	portBASE_TYPE xHigherTaskWoken = pdFALSE;
	uint32_t* in_data_buf = (uint32_t*)g_tm_stick_data.data;
	uint32_t in_data = 0;
	static uint32_t previous_in_data = 0;
	static bool is_first_time = true;
	// calculate the mask needed to wipe off extra high bit junk.
	static uint32_t mask = 0xFFFFFFFF;
	if(is_first_time) {
		for(int i = 4; i > TM_STICK_NUM_DATA_BYTES; i--) {
			mask = mask >> 8;
		}
	}

	if(ssc_is_rx_ready(SSC) == SSC_RC_YES) {
		xSemaphoreTakeFromISR(g_tm_stick_data.mutex, &xHigherTaskWoken);
		in_data = SSC->SSC_RHR;
		// in_data >>= 1; // No idea why it always reads 25bits (one too many bit at the end LSB), instead of 24 I told it to. Therefore, we shift it off.
		in_data = ~in_data; // reverse it. So, now 1 is on, 0 is off.
		in_data &= mask;
		
		// Glitch filtering below.
		if(is_first_time
			||  (previous_in_data ^ in_data) == 0) {
			is_first_time = false;
			*in_data_buf = in_data;
		}
		previous_in_data = in_data;
		xSemaphoreGiveFromISR(g_tm_stick_data.mutex, &xHigherTaskWoken);
	
		xHigherTaskWoken = pdFALSE;
		xSemaphoreGiveFromISR(g_tm_stick_data.rtos_task_semaphore, &xHigherTaskWoken); // if there is an RTOS waiting for the ADC task mutex, wake it up.
		portEND_SWITCHING_ISR(xHigherTaskWoken);
	}
}

#ifdef __cplusplus
}