SAM4S Xplained Pro ADC Demo

Posted on Sep 11, 2016 | 4 comments


SAM4S Xplained Pro ADC Demo

ASF version

Tested for ASF version 3.31.0

ASF Modules required 

  • ADC – Analog-to-digital Converter (driver)

Basic Demo

This demo shows in the screen the light intensity as read by the light sensor. The light sensor creates an output analog voltage, which is a function of the amount of light falling upon the transducer. The ADC converts this voltage to a digital value between 0 and 4096 (12-bits resolution) and places it in one of the ADC registers, from where it can be read by the drivers.

The project requires uses the OLED Drivers module.

See video: Light Sensor Demo.

Code

#include <asf.h>
#include <string.h>


static void configure_adc(void)
{
	/* Configure ADC pin for light sensor. */
	gpio_configure_pin(LIGHT_SENSOR_GPIO, LIGHT_SENSOR_FLAGS);

	/* Enable ADC clock. */
	pmc_enable_periph_clk(ID_ADC);

	/* Configure ADC. */
	adc_init(ADC, sysclk_get_cpu_hz(), 1000000, ADC_MR_STARTUP_SUT0);
	adc_enable_channel(ADC, ADC_CHANNEL_4);
	adc_configure_trigger(ADC, ADC_TRIG_SW, 1);
}

int main(void)
{

	uint32_t adc_value;
	uint32_t normalized_adc_value;
	uint32_t value[6];
	
	sysclk_init();
	board_init();
	ssd1306_init();
	
	//Configure ADC
	configure_adc();

	//start ADC
	adc_start(ADC);
		
	while(true){
			
		// get light sensor information.
		adc_value = adc_get_channel_value(ADC, ADC_CHANNEL_4);

		//normalize
		normalized_adc_value = 35 - (adc_value * 35 / 4096);
	
		//get string with value
		sprintf(value, "%d", adc_value);
	
		//clear screen
		ssd1306_clear();	
		
		//print value
		ssd1306_set_page_address(0);
		ssd1306_set_column_address(0);
		ssd1306_write_text(value);
		
		//print light bar
		ssd1306_set_page_address(3);
		ssd1306_set_column_address(0);
		for(uint32_t i=0; i<normalized_adc_value; i++)
			ssd1306_write_text("/");
		
		delay_ms(15);
	}
	
}

 

Advanced Demo

The demo uses the Light sensor in the IO1 board, and the PWM+ pin in the PROTO1 board. The Light sensor is physically connected to the MCU’s ADC Line 4. Depending on the light intensity the program generates a square wave of variable frequency. The squares wave feed a piezo electric buzzer. PWM drivers must be added to the project.

See video: Light Sensor Buzzer Demo
Code

#include <asf.h>

#define PMWA IOPORT_CREATE_PIN(PIOA, 23) //PWM+ in PROTO1 Board
#define MAX_PERIOD	150 //1.5ms maximum period

static void configure_adc(void);
static void configure_and_start_pwm(void);

pwm_channel_t pwm_opts;

int main(void){
	
	sysclk_init();
	board_init();
	configure_and_start_pwm();
	
	//Configure ADC
	configure_adc();

	//start ADC
	adc_start(ADC);
	
	uint32_t adc_value;
	uint32_t normalized_adc_value;
	uint32_t value[6];
	
	while(true){
		// get light sensor reading
		adc_value = adc_get_channel_value(ADC, ADC_CHANNEL_4);

		//normalize
		normalized_adc_value = MAX_PERIOD - (adc_value * MAX_PERIOD / 4096);

		//update period
		pwm_channel_update_period( PWM, &pwm_opts, normalized_adc_value );
		
		delay_ms(50); //sounds better
	}
}

static void configure_adc(void)
{
	/* Configure ADC pin for light sensor. */
	gpio_configure_pin(LIGHT_SENSOR_GPIO, LIGHT_SENSOR_FLAGS);

	/* Enable ADC clock. */
	pmc_enable_periph_clk(ID_ADC);

	/* Configure ADC. */
	adc_init(ADC, sysclk_get_cpu_hz(), 1000000, ADC_MR_STARTUP_SUT0);
	adc_enable_channel(ADC, ADC_CHANNEL_4);
	adc_configure_trigger(ADC, ADC_TRIG_SW, 1);
}

static void configure_and_start_pwm(void)
{
	//PWM Clock options
	pwm_clock_t pwm_clock_opts = {
		.ul_clka = 100000, //100Khz clock frequency = .01 ms steps
		.ul_clkb = 0,
		.ul_mck =  sysclk_get_main_hz() //main clock speed is 240Mhz!, not 120mhz
	};
	
	//PWM options
	pwm_opts.ul_prescaler = PWM_CMR_CPRE_CLKA;
	pwm_opts.ul_period = MAX_PERIOD; 
	pwm_opts.ul_duty = 7; //10% duty cycle
	pwm_opts.channel = PWM_CHANNEL_0;
	
	//configure IO pins
	pio_configure_pin( PMWA, PIO_TYPE_PIO_PERIPH_B );
	
	//Enable PWM clock
	pmc_enable_periph_clk(ID_PWM);
	
	//disable temporarily
	pwm_channel_disable(PWM, PWM_CHANNEL_0);
	
	//Start PWM
	pwm_init( PWM, &pwm_clock_opts );
	pwm_channel_init( PWM, &pwm_opts );
	pwm_channel_enable( PWM, PWM_CHANNEL_0 );
	
}

 

4 Comments

  1. After extensively searching the Atmel guides, this page helped me fix and issue with my project. Thanks so much for posting this!

    Post a Reply
    • No problem!

      Post a Reply
  2. What are those LIGHT_SENSOR_GPIO, LIGHT_SENSOR_FLAGS

    Thank you for the instructions! It really helps as much as atmel documentation and bloated examples sucks . It would be especially good if you put the examples to GitHub

    Post a Reply
    • From the top of my head… I believe LIGHT_SENSOR_GPIO is defined in some ASF’s header file and specifies the GPIO pin where the Light sensor plugs onto the board. Yes, the Light Sensor plugs to an ADC pin, not GPIO. It’s just that all* pins are GPIO, but some/most can be configured/multiplexed to an alternate function (ADC, TWI, SPI, etc).

      *Not sure it’s actually all of them.

      Post a Reply

Submit a Comment

Your email address will not be published. Required fields are marked *