Ejemplo n.º 1
0
Archivo: timer.c Proyecto: M1cha/lk
void sam_timer_early_init(void)
{
#if 0
	pmc_enable_periph_clk(ID_TC0);


	uint32_t ul_div;
	uint32_t ul_tcclks;
	uint32_t ul_sysclk = MCLK; // sysclk_get_cpu_hz();

	tc_find_mck_divisor(100, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
	tc_init(TC0, 0, TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / 4);

	tc_find_mck_divisor(100, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
	tc_init(TC0, 0, TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, 0xffff); // slowest we can run

	/* Configure and enable interrupt on RC compare */
	NVIC_SetPriority(ID_TC0, arm_cm_highest_priority());
	NVIC_EnableIRQ((IRQn_Type) ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
#endif

	tc_start(TC0, 0);

    arm_cm_systick_init(MCLK);
}
Ejemplo n.º 2
0
void vInitialiseTimerForIntQueueTest( void )
{
uint32_t ulDivider, ulTCCLKS;

	/* Configure PMC for TC0. */
	pmc_enable_periph_clk( ID_TC0 );

	/* Configure TC0 channel 0 for interrupts at tmrTIMER_0_FREQUENCY. */
	tc_find_mck_divisor( tmrTIMER_0_FREQUENCY, configCPU_CLOCK_HZ, &ulDivider, &ulTCCLKS, configCPU_CLOCK_HZ );
	tc_init( TC0, 0, ulTCCLKS | TC_CMR_CPCTRG );
	ulDivider <<= 1UL;
	tc_write_rc( TC0, 0, ( configCPU_CLOCK_HZ / ulDivider ) / tmrTIMER_0_FREQUENCY );
	tc_enable_interrupt( TC0, 0, TC_IER_CPCS );

	/* Configure and enable interrupts for both TC0 and TC1, as TC1 interrupts
	are manually pended from within the TC0 interrupt handler (see the notes at
	the top of this file). */
	NVIC_ClearPendingIRQ( TC0_IRQn );
	NVIC_ClearPendingIRQ( TC1_IRQn );
	NVIC_SetPriority( TC0_IRQn, tmrLOWER_PRIORITY );
	NVIC_SetPriority( TC1_IRQn, tmrHIGHER_PRIORITY );
	NVIC_EnableIRQ( TC0_IRQn );
	NVIC_EnableIRQ( TC1_IRQn );

	/* Start the timer last of all. */
	tc_start( TC0, 0 );
}
Ejemplo n.º 3
0
/**
 * \brief Configure to trigger ADC by TIOA output of timer.
 */
static void configure_time_trigger(void)
{
	uint32_t ul_div = 0;
	uint32_t ul_tc_clks = 0;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();

	/* Enable peripheral clock. */
	pmc_enable_periph_clk(ID_TC0);

	/* TIOA configuration */
	gpio_configure_pin(PIN_TC0_TIOA0, PIN_TC0_TIOA0_FLAGS);

	/* Configure TC for a 1Hz frequency and trigger on RC compare. */
	tc_find_mck_divisor(1, ul_sysclk, &ul_div, &ul_tc_clks, ul_sysclk);
	tc_init(TC0, 0, ul_tc_clks | TC_CMR_CPCTRG | TC_CMR_WAVE |
			TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);
	TC0->TC_CHANNEL[0].TC_RA = (ul_sysclk / ul_div) / 2;
	TC0->TC_CHANNEL[0].TC_RC = (ul_sysclk / ul_div) / 1;

	/* Start the Timer. */
	tc_start(TC0, 0);
	/* Set TIOA0 trigger. */
#if SAM3S || SAM3N || SAM3XA || SAM4S || SAM4C
	adc_configure_trigger(ADC, ADC_TRIG_TIO_CH_0, 0);
#elif SAM3U
#ifdef ADC_12B
	adc12b_configure_trigger(ADC12B, ADC12B_TRIG_TIO_CH_0);
#else
	adc_configure_trigger(ADC, ADC_TRIG_TIO_CH_0);
#endif
#endif
}
Ejemplo n.º 4
0
// [main_tc_configure]
static void configure_tc(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();

	/* Configure PMC */
	pmc_enable_periph_clk(ID_TC0);
#if SAMG55
	/* Enable PCK output */
	pmc_disable_pck(PMC_PCK_3);
	pmc_switch_pck_to_sclk(PMC_PCK_3, PMC_PCK_PRES_CLK_1);
	pmc_enable_pck(PMC_PCK_3);
#endif

	/** Configure TC for a 4Hz frequency and trigger on RC compare. */
	tc_find_mck_divisor(4, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / 4);

	/* Configure and enable interrupt on RC compare */
	NVIC_EnableIRQ((IRQn_Type) ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);

#ifdef LED1_GPIO
	/** Start the counter if LED1 is enabled. */
	if (g_b_led1_active) {
		tc_start(TC0, 0);
	}
#else
	tc_start(TC0, 0);
#endif
}
Ejemplo n.º 5
0
/**
 * \brief Initialize the timer counter (TC0).
 */
void sys_init_timing(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;

	/* Clear tick value. */
	gs_ul_clk_tick = 0;

	/* Configure PMC. */
	pmc_enable_periph_clk(ID_TC0);

	/* Configure TC for a 1kHz frequency and trigger on RC compare. */
	tc_find_mck_divisor(1000,
			sysclk_get_main_hz(), &ul_div, &ul_tcclks,
			sysclk_get_main_hz());
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (sysclk_get_main_hz() / ul_div) / 1000);

	/* Configure and enable interrupt on RC compare. */
	NVIC_EnableIRQ((IRQn_Type)ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);

	/* Start timer. */
	tc_start(TC0, 0);
}
Ejemplo n.º 6
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;
}
/**
 * \brief Configure to trigger AFEC by TIOA output of timer.
 */
static void configure_tc_trigger(void)
{
	uint32_t ul_div = 0;
	uint32_t ul_tc_clks = 0;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();

	/* Enable peripheral clock. */
	pmc_enable_periph_clk(ID_TC0);

	/* TIOA configuration */
	ioport_set_pin_mode(PIN_TC0_TIOA0, PIN_TC0_TIOA0_FLAGS);
	ioport_disable_pin(PIN_TC0_TIOA0);

	/* Configure TC for a 10Hz frequency and trigger on RC compare. */
	tc_find_mck_divisor(10, ul_sysclk, &ul_div, &ul_tc_clks, ul_sysclk);
	tc_init(TC0, 0, ul_tc_clks | TC_CMR_CPCTRG | TC_CMR_WAVE |
			TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);
	TC0->TC_CHANNEL[0].TC_RA = (ul_sysclk / ul_div) / 2;
	TC0->TC_CHANNEL[0].TC_RC = (ul_sysclk / ul_div) / 1;

	/* Start the Timer. */
	tc_start(TC0, 0);

	afec_set_trigger(AFEC0, AFEC_TRIG_TIO_CH_0);
}
Ejemplo n.º 8
0
Archivo: tc.c Proyecto: wugsh/wgs
void tc_trigger_on_freq(Tc* tc, uint32_t channel_num, uint32_t freq)
{
	uint32_t div = 0;
	uint32_t tcclks = 0;
	uint32_t tc_id = get_tc_id_from_addr(tc);
	TcChannel* channel = &tc->TC_CHANNEL[channel_num];

	tc_find_mck_divisor(freq, &div, &tcclks);
	tc_configure(tc, channel_num, tcclks | TC_CMR_CPCTRG);
	channel->TC_RC = (pmc_get_peripheral_clock(tc_id) / div) / freq;
}
Ejemplo n.º 9
0
/**
 * \brief Configure Timer Counter 0 (TC0) to generate an interrupt every 200ms.
 * This interrupt will be used to flush USART input and echo back.
 */
static void configure_tc(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	static uint32_t ul_sysclk;

	/* Get system clock. */
	ul_sysclk = sysclk_get_cpu_hz();

	/* Configure PMC. */
	pmc_enable_periph_clk(ID_TC0);

	/* Configure TC for a 50Hz frequency and trigger on RC compare. */
	tc_find_mck_divisor(TC_FREQ, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / TC_FREQ);

	/* Configure and enable interrupt on RC compare. */
	NVIC_EnableIRQ((IRQn_Type)ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
}
Ejemplo n.º 10
0
/**
 * \brief Configure Timer Counter 0 (TC0) to generate an interrupt every 200ms.
 * This interrupt will be used to flush USART input and echo back.
 */
static void configure_tc(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	static uint32_t ul_pbaclk;

	/* Configure clock service. */
	sysclk_enable_peripheral_clock(TC0);

	/* Get system clock. */
	ul_pbaclk = sysclk_get_peripheral_bus_hz(TC0);

	/* Configure TC for a 1Hz frequency and trigger on RC compare. */
	tc_find_mck_divisor(TC_FREQ, ul_pbaclk, &ul_div, &ul_tcclks, ul_pbaclk);
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (ul_pbaclk / ul_div) / TC_FREQ);

	/* Configure and enable interrupt on RC compare. */
	NVIC_EnableIRQ(TC00_IRQn);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
}
Ejemplo n.º 11
0
/**
 * \brief Configure Timer Counter 0 to generate an interrupt with the specific
 * frequency.
 *
 * \param freq Timer counter frequency.
 */
static void configure_tc(uint32_t freq)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();

	/* Disable TC first */
	tc_stop(TC0, 0);
	tc_disable_interrupt(TC0, 0, TC_IER_CPCS);

	/** Configure TC with the frequency and trigger on RC compare. */
	tc_find_mck_divisor(freq, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / 4);

	/* Configure and enable interrupt on RC compare */
	NVIC_EnableIRQ((IRQn_Type)ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);

	/** Start the counter. */
	tc_start(TC0, 0);
}
Ejemplo n.º 12
0
/**
 *  Configure Timer Counter 0 to generate an interrupt every 200ms.
 */
static void configure_tc(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();

	/* Configure TC0 */
	sysclk_enable_peripheral_clock(TC0);

	/* Configure TC for a 5Hz frequency and trigger on RC compare. */
	if (!tc_find_mck_divisor(5, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk)) {
		puts("No valid divisor found!\r");
		return;
	}
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / 5);

	/* Configure and enable interrupt on RC compare */
	NVIC_EnableIRQ((IRQn_Type) TC00_IRQn);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);

	/* Start the counter. */
	tc_start(TC0, 0);
}
Ejemplo n.º 13
0
/**
 * \brief Configure Timer Counter to generate an interrupt every 10ms.
 * This interrupt will be used to flush UART input and echo back.
 */
static void _configure_TC_uart(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	uint32_t ul_sysclk;
	uint32_t ul_frec_hz = (uint32_t)FREQ_TIMER_POLL_UART;

	/* Get system clock. */
	ul_sysclk = sysclk_get_cpu_hz();

	/* Configure PMC. */
	pmc_enable_periph_clk(ID_TC_UART);

	/* Configure TC for a TC_FREQ frequency and trigger on RC compare. */
	tc_find_mck_divisor(ul_frec_hz, ul_sysclk, &ul_div, &ul_tcclks,
			ul_sysclk);
	tc_init(TC_UART, TC_UART_CHN, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC_UART, TC_UART_CHN, (ul_sysclk / ul_div) / ul_frec_hz);

	/* Configure and enable interrupt on RC compare. */
	NVIC_SetPriority((IRQn_Type)ID_TC_UART, TIMER_UART_PRIO);
	NVIC_EnableIRQ((IRQn_Type)ID_TC_UART);
	tc_enable_interrupt(TC_UART, TC_UART_CHN, TC_IER_CPCS);
}
Ejemplo n.º 14
0
// Here should be all the initialization functions for the module before 12v power
void init_module_peripherals_bp(void)
{
	/* LEDs IO */
	pmc_enable_periph_clk(IN_CLK_LED1_PIO_ID);
	ioport_set_pin_dir(IN_CLK_LED1_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(IN_CLK_LED1_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(IN_CLK_LED2_PIO_ID);
	ioport_set_pin_dir(IN_CLK_LED2_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(IN_CLK_LED2_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(IN_CLK_LED3_PIO_ID);
	ioport_set_pin_dir(IN_CLK_LED3_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(IN_CLK_LED3_GPIO, IOPORT_PIN_LEVEL_HIGH);	
	pmc_enable_periph_clk(IN_DAT_LED1_PIO_ID);
	ioport_set_pin_dir(IN_DAT_LED1_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(IN_DAT_LED1_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(IN_DAT_LED2_PIO_ID);
	ioport_set_pin_dir(IN_DAT_LED2_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(IN_DAT_LED2_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(IN_DAT_LED3_PIO_ID);
	ioport_set_pin_dir(IN_DAT_LED3_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(IN_DAT_LED3_GPIO, IOPORT_PIN_LEVEL_HIGH);	
	pmc_enable_periph_clk(OUT_CH1_CH2_LED1_PIO_ID);
	ioport_set_pin_dir(OUT_CH1_CH2_LED1_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_CH1_CH2_LED1_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(OUT_CH1_CH2_LED2_PIO_ID);
	ioport_set_pin_dir(OUT_CH1_CH2_LED2_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_CH1_CH2_LED2_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(OUT_CH1_CH2_LED3_PIO_ID);
	ioport_set_pin_dir(OUT_CH1_CH2_LED3_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_CH1_CH2_LED3_GPIO, IOPORT_PIN_LEVEL_HIGH);	
	pmc_enable_periph_clk(OUT_CH3_LED1_PIO_ID);
	ioport_set_pin_dir(OUT_CH3_LED1_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_CH3_LED1_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(OUT_CH3_LED2_PIO_ID);
	ioport_set_pin_dir(OUT_CH3_LED2_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_CH3_LED2_GPIO, IOPORT_PIN_LEVEL_HIGH);
	pmc_enable_periph_clk(OUT_CH3_LED3_PIO_ID);
	ioport_set_pin_dir(OUT_CH3_LED3_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_CH3_LED3_GPIO, IOPORT_PIN_LEVEL_HIGH);
	
	/* Pulse inputs/state & d reset output */
	pmc_enable_periph_clk(OUT_PULSE_DET_PIO_ID);
	ioport_set_pin_dir(OUT_PULSE_DET_GPIO, IOPORT_DIR_INPUT);
	pmc_enable_periph_clk(DATA_IN_DET_PIO_ID);
	ioport_set_pin_dir(DATA_IN_DET_GPIO, IOPORT_DIR_INPUT);
	pmc_enable_periph_clk(CLK_IN_DET_PIO_ID);
	ioport_set_pin_dir(CLK_IN_DET_GPIO, IOPORT_DIR_INPUT);	
	pmc_enable_periph_clk(OUT_PULSE_STATE_PIO_ID);
	ioport_set_pin_dir(OUT_PULSE_STATE_GPIO, IOPORT_DIR_INPUT);
	pmc_enable_periph_clk(DATA_IN_STATE_PIO_ID);
	ioport_set_pin_dir(DATA_IN_STATE_GPIO, IOPORT_DIR_INPUT);
	pmc_enable_periph_clk(CLK_IN_STATE_PIO_ID);
	ioport_set_pin_dir(CLK_IN_STATE_GPIO, IOPORT_DIR_INPUT);	
	pmc_enable_periph_clk(OUT_PULSE_RST_PIO_ID);
	ioport_set_pin_dir(OUT_PULSE_RST_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(OUT_PULSE_RST_GPIO, IOPORT_PIN_LEVEL_LOW);	
	pmc_enable_periph_clk(DATA_PULSE_RST_PIO_ID);
	ioport_set_pin_dir(DATA_PULSE_RST_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(DATA_PULSE_RST_GPIO, IOPORT_PIN_LEVEL_LOW);	
	pmc_enable_periph_clk(CLK_PULSE_RST_PIO_ID);
	ioport_set_pin_dir(CLK_PULSE_RST_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(CLK_PULSE_RST_GPIO, IOPORT_PIN_LEVEL_LOW);
	
	/* Sload */
	pmc_enable_periph_clk(DATA_DELAY_SLOAD_PIO_ID);
	ioport_set_pin_dir(DATA_DELAY_SLOAD_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(DATA_DELAY_SLOAD_GPIO, IOPORT_PIN_LEVEL_LOW);
	pmc_enable_periph_clk(CLOCK_DELAY_SLOAD_PIO_ID);
	ioport_set_pin_dir(CLOCK_DELAY_SLOAD_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(CLOCK_DELAY_SLOAD_GPIO, IOPORT_PIN_LEVEL_LOW);
	pmc_enable_periph_clk(RESET_DELAY_SLOAD_PIO_ID);
	ioport_set_pin_dir(RESET_DELAY_SLOAD_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(RESET_DELAY_SLOAD_GPIO, IOPORT_PIN_LEVEL_LOW);
	pmc_enable_periph_clk(RF_ATTEN_SLOAD_PIO_ID);
	ioport_set_pin_dir(RF_ATTEN_SLOAD_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(RF_ATTEN_SLOAD_GPIO, IOPORT_PIN_LEVEL_LOW);

	/* Delay enables */
	pmc_enable_periph_clk(DATA_DELAY_EN_PIO_ID);
	ioport_set_pin_dir(DATA_DELAY_EN_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(DATA_DELAY_EN_GPIO, IOPORT_PIN_LEVEL_HIGH);	// default state is HIGH (OG 10.04.2014)
	pmc_enable_periph_clk(CLOCK_DELAY_EN_PIO_ID);
	ioport_set_pin_dir(CLOCK_DELAY_EN_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(CLOCK_DELAY_EN_GPIO, IOPORT_PIN_LEVEL_HIGH);	// default state is HIGH (OG 10.04.2014)
	pmc_enable_periph_clk(RESET_DELAY_EN_PIO_ID);
	ioport_set_pin_dir(RESET_DELAY_EN_GPIO, IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(RESET_DELAY_EN_GPIO, IOPORT_PIN_LEVEL_HIGH);	// default state is HIGH (OG 10.04.2014)
	
		
	// Init LED interrupt,
	uint32_t ul_div;
	uint32_t ul_tcclks;
	/* Get system clock. */
	uint32_t ul_sysclk = sysclk_get_cpu_hz();
	/* Configure PMC. */
	pmc_enable_periph_clk(ID_TC1);
	/* Configure TC for a TC_FREQ frequency and trigger on RC compare. */
	tc_find_mck_divisor(20, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
	tc_init(TC0, 1, ul_tcclks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 1, (ul_sysclk / ul_div) / 20);
	/* Configure and enable interrupt on RC compare. */
	tc_start(TC0, 1);
	NVIC_DisableIRQ(TC1_IRQn);
	NVIC_ClearPendingIRQ(TC1_IRQn);
	//NVIC_SetPriority(TC1_IRQn, 0);
	NVIC_EnableIRQ((IRQn_Type)ID_TC1);
	tc_enable_interrupt(TC0, 1, TC_IER_CPCS);

	/* SPI interface */
	gpio_configure_pin(SPI0_MISO_GPIO, SPI0_MISO_FLAGS);
	gpio_configure_pin(SPI0_MOSI_GPIO, SPI0_MOSI_FLAGS);
	gpio_configure_pin(SPI0_SPCK_GPIO, SPI0_SPCK_FLAGS);
	//gpio_configure_pin(SPI0_NPCS0_GPIO, SPI0_NPCS0_FLAGS); // Controled by software
	
	/* Configure an SPI peripheral. */
	spi_enable_clock(SPI0);
	spi_disable(SPI0);
	spi_reset(SPI0);
	spi_set_lastxfer(SPI0);
	spi_set_master_mode(SPI0);
	spi_disable_mode_fault_detect(SPI0);
	
	/* Set variable chip select */
	spi_set_variable_peripheral_select(SPI0);
	
	/* Configure delay SPI channel */
	spi_set_clock_polarity(SPI0, SPI_CHIP_SEL, SPI_CLK_POLARITY);
	spi_set_clock_phase(SPI0, SPI_CHIP_SEL, SPI_CLK_PHASE);
	spi_set_bits_per_transfer(SPI0, SPI_CHIP_SEL, SPI_CSR_BITS_11_BIT);
	spi_configure_cs_behavior(SPI0, SPI_CHIP_SEL, SPI_CS_RISE_FORCED);
	spi_set_baudrate_div(SPI0, SPI_CHIP_SEL, (sysclk_get_cpu_hz() / gs_ul_spi_clock));
	spi_set_transfer_delay(SPI0, SPI_CHIP_SEL, SPI_DLYBS, SPI_DLYBCT);
	
	/* Configure RF atten SPI channel */
	spi_set_clock_polarity(SPI0, SPI_ALT_CHIP_SEL, SPI_CLK_POLARITY);
	spi_set_clock_phase(SPI0, SPI_ALT_CHIP_SEL, SPI_CLK_PHASE);
	spi_set_bits_per_transfer(SPI0, SPI_ALT_CHIP_SEL, SPI_CSR_BITS_16_BIT);
	spi_configure_cs_behavior(SPI0, SPI_ALT_CHIP_SEL, SPI_CS_RISE_FORCED);
	spi_set_baudrate_div(SPI0, SPI_ALT_CHIP_SEL, (sysclk_get_cpu_hz() / gs_ul_spi_clock));
	spi_set_transfer_delay(SPI0, SPI_ALT_CHIP_SEL, SPI_DLYBS, SPI_DLYBCT);
	
	/* Enable SPI */
	spi_enable(SPI0);
}
Ejemplo n.º 15
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
}