Arduino Due : two interrupt button and USB MSC example

Discussion around product based on ARM Cortex M3 core.

Moderators: nferre, ncollot

kkk3334
Posts: 2
Joined: Wed Apr 22, 2015 1:39 pm

Arduino Due : two interrupt button and USB MSC example

Wed Jun 10, 2015 6:32 pm

hi all,
I am trying to use two interrupt button with USB MSC in the Arduino Due board.

So, at first I create example project 'USB Host MSC FatFS Exampl - Arduino Due/X'. and than I added some drivers using ASF Wizard and several functions like 'configure_buttons();, set_interrupt_priority(00,000)' etc.

Code: Select all


#include <asf.h>
#include "conf_usb_host.h"
#include "ui.h"
#include "main.h"
#include "string.h"
#include "conf_board.h"
#include "stdio_serial.h"

#define MAX_DRIVE      _VOLUMES
#define TEST_FILE_NAME "0:uhi_msc_test.txt"
#define MSG_TEST "Test UHI MSC\n"

/**
 * Define interrupt priority (0-15). A higher level corresponds to a lower
 * priority, so level 0 is the highest interrupt priority.
 */
#define INT_PRIOR_HIGH    4
#define INT_PRIOR_LOW     6

typedef enum test_state {
	TEST_NULL,
	TEST_OK,
	TEST_NO_PRESENT,
	TEST_ERROR
} test_state_t;

static volatile uint16_t main_usb_sof_counter = 0;

static test_state_t lun_states[MAX_DRIVE];

static FATFS fs; // Re-use fs for LUNs to reduce memory footprint
static FIL file_object;

static char test_file_name[] = {
	TEST_FILE_NAME
};

static void main_reset_states(void);
static int main_count_states(test_state_t state);

/**
 * \brief Delay number of tick Systicks (happens roughly every 1 ms).
 *
 * Note: As the systick has the lowest priority, lower than the PIO, the systick
 * is not used here.
 */
__INLINE static void delay_ticks(uint32_t ul_dly_ticks)
{
	volatile uint32_t ul_delay_tick = (ul_dly_ticks * (BOARD_MCK / 18000));
	while (ul_delay_tick--);
}

 /**
 * \brief Configure LED pins.
 */
__INLINE static void led_config(void)
{
	gpio_set_pin_high(LED0_GPIO);
	gpio_set_pin_high(LED1_GPIO);
}

/**
 * \brief Handler for INT1, rising edge interrupt. In INT1, it will trigger
 *        INT2.
 */
static void Int1Handler(uint32_t ul_id, uint32_t ul_mask)
{
	if (PIN_PUSHBUTTON_1_ID != ul_id || PIN_PUSHBUTTON_1_MASK != ul_mask)
		return;
	pio_disable_interrupt(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_MASK);
	/* Trigger INT1 & Delay for a while. */
	puts("===================================================\r");
	puts("Enter _Int1Handler.\r");

	gpio_set_pin_low(LED0_GPIO);

	delay_ticks(2000);

	gpio_set_pin_high(LED0_GPIO);

	puts("Exit _Int1Handler.\r");
	puts("===================================================\r");
	pio_enable_interrupt(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_MASK);
}

/**
 * \brief Handler for INT2, rising edge interrupt.
 */
static void Int2Handler(uint32_t ul_id, uint32_t ul_mask)
{
	if (PIN_PUSHBUTTON_2_ID != ul_id || PIN_PUSHBUTTON_2_MASK != ul_mask)
		return;

	pio_disable_interrupt(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_MASK);

	puts("***************************************************\r");
	puts("Enter _Int2Handler.\r");
	/* Enter INT2. */
	gpio_set_pin_low(LED1_GPIO);

	/* Delay for a while. */
	delay_ticks(2000);

	/* Exit INT2. */
	gpio_set_pin_high(LED1_GPIO);

	puts("Exit _Int2Handler.\r");
	puts("***************************************************\r");

	pio_enable_interrupt(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_MASK);
}

/**
 * \brief Set interrupt priority of INT1 and INT2.
 *
 * \param int1Prior Priority of interrupt 1.
 * \param int2Prior Priority of interrupt 2.
 *
 * Steps to change the IRQ priority:
 * 1. Disable the interrupt service handler.
 * 2. Clear the pending interrupt service handler.
 * 3. Set the new priority.
 * 4. Enable the interrupt service handler.
 */
static void set_interrupt_priority(uint8_t int1Prior, uint8_t int2Prior)
{
	/* Set INT1 priority. */
	NVIC_DisableIRQ((IRQn_Type) PIN_PUSHBUTTON_1_ID);
	NVIC_ClearPendingIRQ((IRQn_Type) PIN_PUSHBUTTON_1_ID);
	NVIC_SetPriority((IRQn_Type) PIN_PUSHBUTTON_1_ID, int1Prior);
	NVIC_EnableIRQ((IRQn_Type) PIN_PUSHBUTTON_1_ID);

	/* Set INT2 priority. */
	NVIC_DisableIRQ((IRQn_Type) PIN_PUSHBUTTON_2_ID);
	NVIC_ClearPendingIRQ((IRQn_Type) PIN_PUSHBUTTON_2_ID);
	NVIC_SetPriority((IRQn_Type) PIN_PUSHBUTTON_2_ID, int2Prior);
	NVIC_EnableIRQ((IRQn_Type) PIN_PUSHBUTTON_2_ID);
}

/**
*  \brief Configure the push buttons.
*
*  Configure the PIOs as inputs and generate corresponding interrupt when
*  the push buttons are pressed or released.
*/
static void configure_buttons(void)
{
	/* Enable the pmc clocks of the push buttons for all SAM3. */
	pmc_enable_periph_clk(PIN_PUSHBUTTON_1_ID);
	pmc_enable_periph_clk(PIN_PUSHBUTTON_2_ID);

	/* Adjust PIO debouncing filter patameters, using 10 Hz filter. */
	pio_set_debounce_filter(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_MASK, 10);
	pio_set_debounce_filter(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_MASK, 10);

	/* Initialize PIOs interrupt handlers (see PIO definition in board.h). */
	pio_handler_set(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_ID, PIN_PUSHBUTTON_1_MASK, PIN_PUSHBUTTON_1_ATTR, Int1Handler);	/* Interrupt on rising edge.  */
	pio_handler_set(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_ID, PIN_PUSHBUTTON_2_MASK, PIN_PUSHBUTTON_2_ATTR, Int2Handler);	/* Interrupt on falling edge. */




	/* Enable PIO controller IRQs. */
	NVIC_EnableIRQ((IRQn_Type) PIN_PUSHBUTTON_1_ID);
	NVIC_EnableIRQ((IRQn_Type) PIN_PUSHBUTTON_2_ID);

	/* PIO configuration for Buttons. */
	pio_handler_set_priority(PIN_PUSHBUTTON_1_PIO, (IRQn_Type) PIN_PUSHBUTTON_1_ID, 0);
	pio_handler_set_priority(PIN_PUSHBUTTON_2_PIO, (IRQn_Type) PIN_PUSHBUTTON_2_ID, 0);

	/* Enable PIO line interrupts. */
	pio_enable_interrupt(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_MASK);
	pio_enable_interrupt(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_MASK);
}

/**
 *  \brief Configure the Console UART.
 */
static void configure_console(void)
{
	const usart_serial_options_t uart_serial_options = {
		.baudrate = CONF_UART_BAUDRATE,
		.paritytype = CONF_UART_PARITY
	};
	
	/* Configure console UART. */
	sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
	stdio_serial_init(CONF_UART, &uart_serial_options);
}

/**
 * \brief Display menu.
 */
static void display_menu(void)
{
	puts("\n\r"
		"===================================================\n\r"
		"USB MSC example.\n\r"
		"===================================================\n\r"
		"\r");
}

/*! \brief Main function. Execution starts here.
 */
int main(void)
{
#if SAMD21 || SAML21
	system_init();
#else
	sysclk_init();
	board_init();
#endif
	irq_initialize_vectors();
	cpu_irq_enable();

	// Initialize the sleep manager
	//sleepmgr_init();

	//ui_init();

	// Start USB host stack
	uhc_start();

	// The USB management is entirely managed by interrupts.
	// As a consequence, the user application does only have :
	// - to play with the power modes
	// - to create a file on each new LUN connected
	
	/* Initialize the console uart */
	configure_console();

	/* configure LED. */
	led_config();

	/* configure push buttons. */
	configure_buttons();

	/* Set default priorities for 2 buttons. */
	set_interrupt_priority(INT_PRIOR_HIGH, INT_PRIOR_LOW);

	/* Display the main menu. */
	display_menu();
	
	while (true) {
		//sleepmgr_enter_sleep();
		if (main_usb_sof_counter > 2000) {
			main_usb_sof_counter = 0;
			volatile uint8_t lun;
			FRESULT res;

			for (lun = LUN_ID_USB; (lun < LUN_ID_USB + uhi_msc_mem_get_lun()) && (lun < MAX_DRIVE); lun++) {
				// Check if LUN has been already tested
				if (TEST_OK == lun_states[lun] || TEST_ERROR == lun_states[lun]) {
					continue;
				}
				// Mount drive
				memset(&fs, 0, sizeof(FATFS));
				res = f_mount(lun, &fs);
				if (FR_INVALID_DRIVE == res) {
					// LUN is not present
					lun_states[lun] = TEST_NO_PRESENT;
					continue;
				}
				// Create a test file on the disk
				test_file_name[0] = lun + '0';
				res = f_open(&file_object, (char const *)test_file_name, FA_CREATE_ALWAYS | FA_WRITE);
				if (res == FR_NOT_READY) {
					// LUN not ready
					lun_states[lun] = TEST_NO_PRESENT;
					f_close(&file_object);
					continue;
				}
				if (res != FR_OK) {
					// LUN test error
					lun_states[lun] = TEST_ERROR;
					f_close(&file_object);
					continue;
				}
				// Write to test file
				f_puts(MSG_TEST, &file_object);
				f_printf(&file_object, "\r\n test f_printf \r\n");
				// LUN test OK
				lun_states[lun] = TEST_OK;
				f_close(&file_object);
			}
			if (main_count_states(TEST_NO_PRESENT) == MAX_DRIVE) {
				ui_test_finish(false); // Test fail
			} else if (MAX_DRIVE != main_count_states(TEST_NULL)) {
				if (main_count_states(TEST_ERROR)) {
					ui_test_finish(false); // Test fail
				} else if (main_count_states(TEST_OK)) {
					ui_test_flag_reset();
					ui_test_finish(true); // Test OK
				}
			} else {
				ui_test_flag_reset();
			}
		}
	}
}

void main_usb_sof_event(void)
{
	main_usb_sof_counter++;
	ui_usb_sof_event();
}

void main_usb_connection_event(uhc_device_t * dev, bool b_present)
{
	if (!b_present) {
		main_reset_states(); // LUN is unplugged, reset flags
	}
	ui_usb_connection_event(dev, b_present);
}

static void main_reset_states(void)
{
	int i;
	for (i = 0; i < MAX_DRIVE; i ++) {
		lun_states[i] = TEST_NULL;
	}
}

static int main_count_states(test_state_t state)
{
	int i, count = 0;
	for (i = 0; i < MAX_DRIVE; i ++) {
		if (lun_states[i] == state) {
			count ++;
		}
	}
	return count;
}
This project was almost working well. But the problem appeared in the Button2.
It doesn't action. I effort and try reading datasheet and changing something.
And I found that, It was working when disable the function 'uhc_start()'
but USB MSC do not work if disable 'uhc_start()'.

I tried so long time to solve the problem, but I can't.

Please advice for me If anybody know reason of the problem which when the two functions working together NVIC interrupt function and USB MSC .


**if you need project file, please enter hear. thanks.
https://drive.google.com/drive/folders/ ... HVjb0FFYlk
Bogdancev
Posts: 9
Joined: Sun Jul 13, 2014 3:13 pm

Re: Arduino Due : two interrupt button and USB MSC example

Tue Aug 11, 2015 8:41 am

First of all Arduino Due examples are not always working. I encountered it twice, with simple UART example and USB host example, because Arduino Due board has additional components but examples were probably written for SAM3X that is on some other board or something like that.

Second, if you are using ASF example, please try to dig dipper into their functions - you will be amazed how many unnecessary things are done inside and some of those things might interfere with others. What I did, I draw a graph of all function calls and what they did to understand what's going on.

So probably there are some electrical connections and components on board (like transistors, etc.) that might invert logical levels - for instance, in an example you output 0, but in reality you need to output 1 to make it work correctly.

Anyway, in you case it should be simple as one of two buttons works. Please go to Arduino.cc web-site, open Arduino Due schematic and see the difference between those two pins. Do one of them have something that is also connected to it?

Regards, Sergiy

Return to “SAM3 Cortex-M3 MCU”

Who is online

Users browsing this forum: No registered users and 2 guests