Skip to content
Amin edited this page Jul 30, 2016 · 3 revisions

init.c

port_init()

Port masks are defined in conf_board.h. SPI lines(CS, MOSI and SCL) should be high before initiating nRF24l01. There are two interrupts on ATxmega pins : NRF24L01_IRQ_LINE, KICK_SENSOR

void port_init(void)
{
	PORTA.DIR = MASK_PORTA;
	PORTB.DIR = MASK_PORTB;
	PORTC.DIR = MASK_PORTC;
	PORTD.DIR = MASK_PORTD;
	PORTE.DIR = MASK_PORTE;
	PORTF.DIR = MASK_PORTF;
	PORTR.DIR = MASK_PORTR;

	ioport_set_value(NRF24L01_CS_LINE  , IOPORT_PIN_LEVEL_HIGH);
	ioport_set_value(NRF24L01_MOSI_LINE, IOPORT_PIN_LEVEL_HIGH);
	ioport_set_value(NRF24L01_SCK_LINE , IOPORT_PIN_LEVEL_HIGH);
	
	ioport_configure_pin(NRF24L01_IRQ_LINE, PORT_ISC_FALLING_gc | PORT_OPC_PULLUP_gc);
	ioport_configure_pin(KICK_SENSOR,PORT_ISC_FALLING_gc);
	PORTD.INTCTRL  = PORT_INT0LVL_HI_gc | PORT_INT1LVL_HI_gc;
	PORTD.INT0MASK = ioport_pin_to_mask(NRF24L01_IRQ_LINE);
	PORTD.INT1MASK = ioport_pin_to_mask(KICK_SENSOR);
}

spi_init()

NRF24L01_SPI ~ SPID

  • Baud rate : 8MHz

  • Mode : Master

void spi_init(void)
{
	sysclk_enable_peripheral_clock(&NRF24L01_SPI);
	spi_xmega_set_baud_div(&NRF24L01_SPI,8000000UL,F_CPU);
	spi_enable_master_mode(&NRF24L01_SPI);
	spi_enable(&NRF24L01_SPI);
}

nrf_init ()

NRF24L01_Init_milad :

  • Mode : radio receiver (_RX_MODE)

  • Channel : _CH_1(2401MHz) or _CH_0(2450MHz) depending on RobotID

  • Air data rate = 2 Mbps

  • Address : setting in robot_id_set()

  • Address Width : 5

  • Buffer Size : 32 (size of wireless packet)

  • Transmit Power : max ~ 0dB

NRF24L01_WriteReg(W_REGISTER | DYNPD,0x01) : Enable dynamic payload length data pipe 0.

NRF24L01_WriteReg(W_REGISTER | FEATURE,0x06) : Enables Dynamic Payload Length and Enables Payload with ACK

void nrf_init (void)
{
	//NRF24L01_CE_LOW;       //disable transceiver modes
	delay_ms(100); 
	NRF24L01_Clear_Interrupts();
	NRF24L01_Flush_TX();
	NRF24L01_Flush_RX();
	//NRF24L01_CE_LOW;
	if (RobotID < 6)
	NRF24L01_Init_milad(_RX_MODE, _CH_1, _2Mbps, Address, _Address_Width, _Buffer_Size, RF_PWR_MAX);
	else if(RobotID > 5)
	NRF24L01_Init_milad(_RX_MODE, _CH_0, _2Mbps, Address, _Address_Width, _Buffer_Size, RF_PWR_MAX);
	NRF24L01_WriteReg(W_REGISTER | DYNPD,0x01);
	NRF24L01_WriteReg(W_REGISTER | FEATURE,0x06);

	NRF24L01_CE_HIGH;//rx mode  ?
	delay_us(130);
}

robot_id_set()

It sets robot's address for wireless communication.

void robot_id_set(void)
{
	Address[4] = (RobotID << 4 ) | RobotID ;
}

evsys_init()

It configures event channels for cascading two TCs to other TCs.

void evsys_init(void)
{
  sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);
  //EVSYS.CH3MUX = EVSYS_CHMUX_PORTD_PIN2_gc; If it is needed to trig adc from NRF24L01 IRQ
  EVSYS.CH1MUX = EVSYS_CHMUX_TCD1_OVF_gc;
  EVSYS.CH2MUX = EVSYS_CHMUX_TCE0_OVF_gc;
}

##adc_init()

  • Trigger : Event-triggered conversion sweeps (event channels are activated manualy in read_all_adc() )

  • adc_calibration() : measures offset and gain of ADC modules

void adc_init(void)
{
	//! ADCA
	struct adc_config adc_conf;
	struct adc_channel_config adcch_conf;
	adc_read_configuration(&ADCA, &adc_conf);
	adcch_read_configuration(&ADCA, ADC_CH0, &adcch_conf);
	adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_12, ADC_REF_AREFB);
	adc_set_conversion_trigger(&adc_conf, ADC_TRIG_EVENT_SWEEP, 4, 0);
	adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE);
	adc_set_clock_rate(&adc_conf, 200000UL);
	adc_write_configuration(&ADCA, &adc_conf);
	
	//! MPU temperature
	adcch_set_input(&adcch_conf, ADCCH_POS_TEMPSENSE, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCA, ADC_CH0, &adcch_conf);
	//! Battery voltage
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN3, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCA, ADC_CH1, &adcch_conf);
	//! M2
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN5, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCA, ADC_CH2, &adcch_conf);
	//! M3
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN6, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCA, ADC_CH3, &adcch_conf);
	
	adc_enable(&ADCA);
	
	//! ADCB
	adc_read_configuration(&ADCB, &adc_conf);
	adcch_read_configuration(&ADCB, ADC_CH0, &adcch_conf);
	adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_12, ADC_REF_AREFB);
	adc_set_conversion_trigger(&adc_conf, ADC_TRIG_EVENT_SWEEP, 3, 0);
	adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE);
	adc_set_clock_rate(&adc_conf, 200000UL);
	adc_write_configuration(&ADCB, &adc_conf);
	
	//! M0
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN2, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCB, ADC_CH0, &adcch_conf);
	//! M1
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN1, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCB, ADC_CH1, &adcch_conf);
	//! BANDGAP
	adcch_set_input(&adcch_conf, ADCCH_POS_BANDGAP, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&ADCB, ADC_CH2, &adcch_conf);
	
	adc_enable(&ADCB);
	
	adc_calibration();	
}

##adc_calibration () Analog signals and digital values have a linear relationship. But slope coefficient and constant offset should be found in order to convert digital values to analog values. We find them with the help of two specific points :

  • adc_bandgap (a reference in ADC module : 1.1 V)

  • 0 V when a pin output is low

void adc_calibration (void)
{
	//! Help : ADC_result = adc_gain * voltage + adc_offset
	
	ioport_set_pin_dir(MOTOR0_CURRENT_ADC,IOPORT_DIR_OUTPUT);
	ioport_set_pin_dir(MOTOR1_CURRENT_ADC,IOPORT_DIR_OUTPUT);
	ioport_set_pin_dir(MOTOR2_CURRENT_ADC,IOPORT_DIR_OUTPUT);
	ioport_set_pin_dir(MOTOR3_CURRENT_ADC,IOPORT_DIR_OUTPUT);
	ioport_set_pin_level(MOTOR0_CURRENT_ADC,low);
	ioport_set_pin_level(MOTOR1_CURRENT_ADC,low);
	ioport_set_pin_level(MOTOR2_CURRENT_ADC,low);
	ioport_set_pin_level(MOTOR3_CURRENT_ADC,low);
	
	for (int i=10; i ; i-- )
	{
		EVSYS.DATA = 0x01;
		EVSYS.STROBE = 0x01;
		delay_ms(1); //! Time needed for good result (tested)
		adc_m2_offset           += adc_get_result(&ADCA, ADC_CH2);
		adc_m3_offset           += adc_get_result(&ADCA, ADC_CH3);
		adc_m0_offset           += adc_get_result(&ADCB, ADC_CH0);
		adc_m1_offset           += adc_get_result(&ADCB, ADC_CH1);
		adc_bandgap             += adc_get_result(&ADCB, ADC_CH2);
		             
		adc_clear_interrupt_flag(&ADCA, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3);
		adc_clear_interrupt_flag(&ADCB, ADC_CH0 | ADC_CH1 );	
	}
	
	adc_m2_offset       = adc_m2_offset	 / 10 ;
	adc_m3_offset       = adc_m3_offset	 / 10 ;
	adc_m0_offset       = adc_m0_offset	 / 10 ;
	adc_m1_offset       = adc_m1_offset  / 10 ;
	adc_bandgap         = adc_bandgap    / 10 ;
	
	adc_offset = (adc_m0_offset + adc_m1_offset + adc_m2_offset + adc_m3_offset) / 4 ;
	adc_gain   = (adc_bandgap - adc_offset) / 1.1 ;
	
	ioport_set_pin_dir(MOTOR0_CURRENT_ADC,IOPORT_DIR_INPUT);
	ioport_set_pin_dir(MOTOR1_CURRENT_ADC,IOPORT_DIR_INPUT);
	ioport_set_pin_dir(MOTOR2_CURRENT_ADC,IOPORT_DIR_INPUT);
	ioport_set_pin_dir(MOTOR3_CURRENT_ADC,IOPORT_DIR_INPUT);
}

current_sensor_offset ()

Calculates mean of current sensor outputs when all motors are off (free wheel).

void current_sensor_offset (void)
{
	if (!current_offset_check)
	{
		if ( (abs(Robot.W0.full)< 5) && (abs(Robot.W1.full)< 5) && (abs(Robot.W2.full)< 5) && (abs(Robot.W3.full)< 5) )
		{
			delay_ms(50);
			current_offset_check = true;
			for (int i=50; i ; i-- )
			{
				EVSYS.DATA = 0x01;
				EVSYS.STROBE = 0x01;
				delay_ms(1); //! Time needed for good result (tested)
				adc_m2_offset           += adc_get_result(&ADCA, ADC_CH2);
				adc_m3_offset           += adc_get_result(&ADCA, ADC_CH3);
				adc_m0_offset           += adc_get_result(&ADCB, ADC_CH0);
				adc_m1_offset           += adc_get_result(&ADCB, ADC_CH1);
		
				adc_clear_interrupt_flag(&ADCA, ADC_CH0 | ADC_CH1 | ADC_CH2 | ADC_CH3);
				adc_clear_interrupt_flag(&ADCB, ADC_CH0 | ADC_CH1 );
			}
	
			adc_m0_offset       = (adc_m0_offset	 / 50 - adc_offset) / adc_gain;
			adc_m1_offset       = (adc_m1_offset	 / 50 - adc_offset) / adc_gain;
			adc_m2_offset       = (adc_m2_offset	 / 50 - adc_offset) / adc_gain;
			adc_m3_offset       = (adc_m3_offset     / 50 - adc_offset) / adc_gain;
			}
			
			if ( (abs(Robot.W0.full)> 5) || (abs(Robot.W1.full)> 5) || (abs(Robot.W2.full)> 5) || (abs(Robot.W3.full)> 5) )
			{
				current_offset_check = false;
			}
	}
}

tc_init()

  • TCD1 and TCF0 are cascaded
  • TCE0 and TCE1 are cascaded
void tc_init(void)
{
  /* Boost & buck pins:
   * charge & kick : C2
   *(other TC settings should be done according to the type of use )
   */
  tc_enable(&TCC0);
  tc_set_wgm(&TCC0, TC_WG_SS);
  tc_write_clock_source(&TCC0, TC_CLKSEL_DIV64_gc);
  
 
  /** chip : pin C4 
	* (other TC settings should be done according to the type of use )
	*/
  tc_enable(&TCC1);
  tc_set_wgm(&TCC1, TC_WG_SS);
  tc_write_clock_source(&TCC1, TC_CLKSEL_DIV64_gc);
  
  //! Clock : 250ms
  tc_enable(&TCD0);
  tc_set_overflow_interrupt_callback(&TCD0, every_250ms);
  tc_set_wgm(&TCD0, TC_WG_NORMAL);
  tc_write_period(&TCD0, 31250);
  tc_set_overflow_interrupt_level(&TCD0, TC_INT_LVL_LO);
  tc_write_clock_source(&TCD0, TC_CLKSEL_DIV256_gc);
  
  //! Boost & buck circuit timer : 1ms
  tc_enable(&TCD1);
  tc_set_wgm(&TCD1, TC_WG_NORMAL);
  tc_write_period(&TCD1, 500);
  tc_write_clock_source(&TCD1, TC_CLKSEL_DIV64_gc);//! Overflow every 1ms
  
  tc_enable(&TCF0);
  tc_set_wgm(&TCF0, TC_WG_NORMAL);
  tc_write_period(&TCF0, 0xFFFF);
  tc_write_clock_source(&TCF0, TC_CLKSEL_EVCH1_gc);//! Frequency of EVENT_CHANEL1 = 1kHz
  
  //! Functions timing
  tc_enable(&TCE0);
  tc_set_wgm(&TCE0, TC_WG_NORMAL);
  tc_write_period(&TCE0, 500);
  tc_write_clock_source(&TCE0, TC_CLKSEL_DIV64_gc);
  
  tc_enable(&TCE1);
  tc_set_wgm(&TCE1, TC_WG_NORMAL);
  tc_write_period(&TCE1, 0xFFFF);
  tc_write_clock_source(&TCE1, TC_CLKSEL_EVCH2_gc);
	
}
Clone this wiki locally