SAM4E16C – Problems with IO-driver functions

Discussion around product based on ARM Cortex M4 core.

Moderators: nferre, ncollot

Posts: 5
Joined: Wed Mar 11, 2015 6:33 pm

SAM4E16C – Problems with IO-driver functions

Wed Mar 11, 2015 6:39 pm

Hello everyone,
i am currently working on a board with a SAM4E16C microcontroller on it as a part of a thesis for my studies. The board has a couple of peripheral devices (Ethernet, SD, ADC, CAN,....), but the problem i am facing right now regards the io-functions used for checking a button-matrix. Currently im working with Atmel Studio 6.2 and program via JTAG with a SAM-ICE.

The button-matrix is a 3x4 matrix, where all coloumns are on a 3,3V high level by default. The rows are alternatly and periodically set (every 1 ms the next row) on a low level. If a button is pressed, the row signal can be read on the column. After a 1ms settling time, the columns are checked for a low level signal. When finding a match, the button number can be calculated with the actual row and column number.
This matrix was added to the design after an overhaul of the board and im currently updating the test suite for the board. Now to the problem:

When first testing the updated code, it worked with 8 out of 12 buttons. I worked and augmented the old test project and after testing the lines and pins with an oscilloscope, i found out that the project was based on a SAM4E16E chipset, which is a 144-pin microcontroller instead of a 100-pin model.

I created a new project for a SAM416C model and added the core ASF drivers for the tests:
- FreeRTOS(7.3.0)
- SystemClock
and copied the core code into the project, which consists of 2 RTOS tasks and a small main function. The task task_Buttons checks the signals every ms and sends the button number into the censored for the task_ButtonReaction, which will only trigger LEDs according to the button number.

The previous problem of not sending signals on a pin for a row disappeared and the signal course is now perfectly fine. Instead a new problem occurred, where the IO driver function ioport_get_pin_level would always recieve a low level input. As an output i can set high or low level values on the port, so it is accessable, but when trying to read the value, i will always recieve a low level. The wire was checked with an oscilloscope and the signal shows the right behaviour, so i suppose, that the problem lies somewhere within the function ioport_get_pin_level ,where val_col tries to read the pin level.

I checked every line of the code multiple times and narrowed it down to the small part where the switch case checks the collumn input. The same code works with most of the pins in the project based on a SAM4E16E. If anyone has suggestions, which part could cause the problems, i could really appreciate those. If anything is unclear, i will gladly add the missing details.

Code is below:

Code: Select all

#include <asf.h>
#include <string.h>
#include <stdint.h>
#include "conf_board.h"
#include "IO_PINS.h"

/***************Defines for the tasks****************************/
xQueueHandle QueueButtons;

xTaskHandle task_buttonreaction ;
xTaskHandle task_buttons ;

void task_Buttons(void *pvParameters);
void task_ButtonReaction(void *pvParameters);

void task_ButtonReaction(void *pvParameters){
	char button_pressed = 0;
		switch (button_pressed){
			case 1:		ioport_set_pin_level(MATRIX_LED1,IOPORT_PIN_LEVEL_HIGH); break;
			case 2:		ioport_set_pin_level(MATRIX_LED1,IOPORT_PIN_LEVEL_LOW); break;
			case 3:		led_toggle(1); break;
			case 4:		led_on(3); break;
			case 5:		led_off(3); break;
			case 6:		led_toggle(3); break;
			case 7:		led_on(4); break;
			case 8:		led_off(4); break;
			case 9:		led_toggle(4); break;
			case 10:	led_on(5);break;
			case 11:	led_off(5);break;
			case 12:	led_toggle(5);break;
			default:	break;


void task_Buttons(void *pvParameters){
	unsigned char val_col = 1;
	char butten_number=0, old_button1=0, old_button2=0, old_button3=0, old_button4=13, row=0;
		for (int col=0;col<=2;col++){							// Loop for the Button Columns
			switch (col){										// Saves the value for the actual column
				case 0: val_col = ioport_get_pin_level(BUTTON_COL1);	break;
				case 1: val_col = ioport_get_pin_level(BUTTON_COL2);	break;
				case 2: val_col = ioport_get_pin_level(BUTTON_COL3);	break;
			if(!(val_col==0)){									// When val_col==0 a button was pressed
				butten_number=(row)*3+(col+1);					// Calculates the button number (1-12) by row+column
		// Checks if the last three results match (button pressed) and the recent one differs (button released)
		if ((old_button4==old_button3)&&(old_button3==old_button2)&&(old_button2==old_button1)&&(old_button1!=butten_number)){
			butten_number=0; old_button1=0;	old_button2=0;	old_button3=0; old_button4=13;
		} else {			// Saves the last results for the check
			old_button4= old_button3; old_button3=old_button2; old_button2=old_button1; old_button1=butten_number;
		// Resets the ROW-pins to "1"
		switch (row){
			case 0: ioport_set_pin_level(BUTTON_ROW1,IOPORT_PIN_LEVEL_HIGH); break;
			case 1: ioport_set_pin_level(BUTTON_ROW2,IOPORT_PIN_LEVEL_HIGH); break;
			case 2: ioport_set_pin_level(BUTTON_ROW3,IOPORT_PIN_LEVEL_HIGH); break;
			case 3: ioport_set_pin_level(BUTTON_ROW4,IOPORT_PIN_LEVEL_HIGH); break;
		// Selects next row and sets the level of this row to "0"
		if (row==3)	{ row=0; } else { row++; }
		switch (row){
			case 0: ioport_set_pin_level(BUTTON_ROW1,IOPORT_PIN_LEVEL_LOW); break;
			case 1: ioport_set_pin_level(BUTTON_ROW2,IOPORT_PIN_LEVEL_LOW); break;
			case 2: ioport_set_pin_level(BUTTON_ROW3,IOPORT_PIN_LEVEL_LOW); break;
			case 3: ioport_set_pin_level(BUTTON_ROW4,IOPORT_PIN_LEVEL_LOW); break;

int main (void)
	/* Initialize the SAM system */
	//LEDs and pushbuttons
	ioport_set_port_dir(PORTA, MATRIX_MASK_LED, IOPORT_DIR_OUTPUT);	// IO_Out LEDs
	ioport_set_port_dir(PORTA, BUTTON_MASK_OUT, IOPORT_DIR_OUTPUT);	// all button-matrix rows
	ioport_set_port_dir(PORTA, BUTTON_MASK_IN, IOPORT_DIR_INPUT);	// all button-matrix collumns
	ioport_set_port_mode(PORTA, BUTTON_MASK_IN, IOPORT_MODE_PULLUP);// PullUp for collumns
	for (char u=1;u<=5;u++){ led_off(u);}

	xTaskCreate(task_ButtonReaction,"ButtonReaction", configMINIMAL_STACK_SIZE, NULL, 4, &task_buttonreaction);
	xTaskCreate(task_Buttons,"Buttons", configMINIMAL_STACK_SIZE, NULL, 3, &task_buttons);

	/* Start the scheduler. */
	return 0;
Posts: 5
Joined: Wed Mar 11, 2015 6:33 pm

Re: SAM4E16C – Problems with IO-driver functions

Wed Mar 18, 2015 12:01 pm

The problem can be reduced to code in the task_Buttons and it would show the problem with the IO function.
The code here works only with the the first row of buttons. When one of those buttons is pressed, the LED should be on, but this code does not work with the Chipset drivers for the SAM4E16C, but it DOES WORK with the SAM4E16E code.

Code: Select all

void task_Buttons(void *pvParameters){
	unsigned char val_col = 1;
		val_col = ioport_get_pin_level(BUTTON_COL1);
		if(!(val_col==0)){									// When val_col==0 a button was pressed

Can anyone guess why the ioport_get_pin_level will not work with the correct drivers?
Posts: 5
Joined: Wed Mar 11, 2015 6:33 pm

Re: SAM4E16C – Problems with IO-driver functions

Fri Mar 20, 2015 10:49 am

I guess i found the mistake. After checking the initializing functions and comparing them, i found out that the new project had not included the ioport_init(); in the board_init(); , so after adding it, the problem was resolved.
I also rechecked the pins for extra functions and there were no entries, but the tip got me on the right track.

Return to “SAM4 Cortex-M4 MCU”

Who is online

Users browsing this forum: No registered users and 1 guest