Sam3x Arduino Due HC-SR04 with interrupts, reduce ASF layers

jstampfl's picture
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Type: 

Compiler/Assembler: 

AS7  1006.  Began with the "Getting-Started" ASF example for the Arduino Due/Sam3x board.

 

NOTE:  The HC-SR04 is a 5 volt device.  YOU MUST USE A LEVEL SHIFTER ON THE ECHO LINE.

 

The 3.3 volt trigger works fine as is.

 

Hardware connection is:  Trigger pin on Arduino pin 09 and the echo on Arduino pin 12 via the level shifter.  Connect the Arduino 5v to VCC and GND to GND.

 

Here is a Arduino sketch that will test the operation.

 

/* Ping))) Sensor

   This sketch reads a PING))) ultrasonic rangefinder and returns the
   distance to the closest object in range. To do this, it sends a pulse
   to the sensor to initiate a reading, then listens for a pulse
   to return.  The length of the returning pulse is proportional to
   the distance of the object from the sensor.

   The circuit:
	* +V connection of the PING))) attached to +5V
	* GND connection of the PING))) attached to ground
	* SIG connection of the PING))) attached to digital pin 7

   http://www.arduino.cc/en/Tutorial/Ping

   created 3 Nov 2008
   by David A. Mellis
   modified 30 Aug 2011
   by Tom Igoe

   This example code is in the public domain.

 */

// this constant won't change.  It's the pin number
// of the sensor's output:
const int trigPin = 9;
const int echoPin = 12;
void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration, inches, cm;

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  //pinMode(pingPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(trigPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  //pinMode(pingPin, INPUT);
  duration = pulseIn(echoPin, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);

  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

  delay(1000);
}

long microsecondsToInches(long microseconds) {
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

This will run on An Arduino UNO, but the level shifter isn't needed.

 

I used an Atmel ICE as the debugger/programmer.  Connect to the JTAG port on the Arduino Due.

 

Here is the ASF modified code.  After starting an example of "Getting-Started" in ASF, replace the main.c with the following main.c.

 

Note:  The PIOD_Hander in pio_handler.c must be commented out.  The PIOD-Handler in main.c will be used.

 

/**
 *
 *  Sam3x - Arduino Due HC-SR04 with interrupts
 *
 *  Copyright (c) 2016  John Stampfl
 *
 *  This project is to remove as many ASF layers as I can. Using the HC-SR04 an an
 *  example.
 *  NOTE:  You need to comment out the PIOD_Handler in:
 * "src/ASF/sam/drivers/pio/pio_handler.c"
 *
 *
 * \brief Getting Started Application.
 *
 * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
  *
  * \page License
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
  * 1. Redistributions of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  *
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  *
  * 3. The name of Atmel may not be used to endorse or promote products derived
  *    from this software without specific prior written permission.
  *
  * 4. This software may only be redistributed and used in connection with an
  *    Atmel microcontroller product.
  *
  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * \asf_license_stop
  *
  */
#include "asf.h"
#include "stdio_serial.h"
#include "conf_board.h"
#include "conf_clock.h"
#define STRING_HEADER "-- Getting Started Example --\r\n" \
		"-- "BOARD_NAME" --\r\n" \
		"-- Compiled: "__DATE__" "__TIME__" --\r\n"

volatile uint32_t g_ul_ms_ticks = 0; // [main_var_ticks]

volatile uint32_t state,time,cnt;
volatile uint32_t status;

void SysTick_Handler(void)
{
	g_ul_ms_ticks++;
}

void PIOD_Handler()					//[main_Echo interrupt_handler]
{
	tc_stop(TC0, 0);
	status = pio_get_interrupt_status(PIOD);
	status &= pio_get_interrupt_mask(PIOD);
	if (state == 3)
	{
		state = 5;
		time = tc_read_cv(TC0,0);
	} else
	if (state == 2)
	{
		state = 3;
		tc_write_rc(TC0,0,2000000U);
		tc_start(TC0,0);
	} else
	{
		state = 0;
	}
}

static void configure_trig(void)	//Trigger pin
{
	PIOC->PIO_PUDR = PIO_PC21;
	PIOC->PIO_CODR = PIO_PC21;
	PIOC->PIO_OER  = PIO_PC21;
}

static void configure_Echo(void)	//Echo pin
{
	uint32_t bitmask;
	pmc_enable_periph_clk(ID_PIOD);
	bitmask = PIOD->PIO_IMR | PIO_PD8;
	PIOD->PIO_IDR = 0XFFFFFFFF;
	PIOD->PIO_ISR;
	NVIC_DisableIRQ((IRQn_Type) ID_PIOD);
	NVIC_ClearPendingIRQ((IRQn_Type) ID_PIOD);
	NVIC_EnableIRQ((IRQn_Type) ID_PIOD);
	PIOD->PIO_ISR;
	PIOD->PIO_IER = bitmask;
	PIOD->PIO_MDER = PIO_PD8;
}

void TC0_Handler(void)
{
	tc_stop(TC0,0);
	tc_get_status(TC0, 0);
	if (state == 1)
	{
		state = 2;
		PIOC->PIO_CODR = PIO_PC21;
	} else
	{
		state = 0;
	}
}

static void configure_tc(void)
{
	pmc_enable_periph_clk(ID_TC0);
	tc_init(TC0, 0, TC_CMR_CPCTRG);
	NVIC_EnableIRQ((IRQn_Type) ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
}

static void configure_console(void)
{
	const usart_serial_options_t uart_serial_options = {
		.baudrate = 250000,
#ifdef CONF_UART_CHAR_LENGTH
		.charlength = CONF_UART_CHAR_LENGTH,
#endif
		.paritytype = CONF_UART_PARITY,
#ifdef CONF_UART_STOP_BITS
		.stopbits = CONF_UART_STOP_BITS,
#endif
	};
	sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
	stdio_serial_init(CONF_UART, &uart_serial_options);
}

static void mdelay(uint32_t ul_dly_ticks)
{
	uint32_t ul_cur_ticks;

	ul_cur_ticks = g_ul_ms_ticks;
	while ((g_ul_ms_ticks - ul_cur_ticks) < ul_dly_ticks);
}

int main(void)
{
	cnt = 0;
	uint32_t sum = 0;
	int i = 0;
	int mm = 0;
	int cm = 0;
	sysclk_init();
	board_init();
	configure_trig();
	configure_Echo();
	configure_console();
	puts(STRING_HEADER);
										//! [main_step_systick_init]
	if (SysTick_Config(84000000U / 1000U)) {
		puts("-F- Systick configuration error\r");
		while (1);
	}
										//! [main_step_systick_init]
	configure_tc();

	PIOC->PIO_CODR = PIO_PC21;			//Low level on trigger pin
	mdelay(2);							//for a short time.
	printf("start\r\n");

	while (1)
	{
		if (state == 0)
		{
		PIOC->PIO_SODR = PIO_PC21;		//High level on trigger &
		tc_write_rc(TC0,0,880U);
		tc_start(TC0,0);				//start timer
		state = 1;
		}
		if (state == 2)
		{
			cnt++;						//no reason now.
		}

		if (state == 5)
		{
			i++;
			sum = sum + time;
			if (i == 8)
			{
				sum = sum/8;
				i = 1;
				mm = (sum +8083)/252;
				cm = (mm + 5)/10;
				printf("time = %u, mm = %d, cm = %d\r\n",(unsigned int)sum,mm,cm);
			}
			time = 0;
			state = 0;
			mdelay(500);
		}
	}
}