Maker Pro
Maker Pro

Atmel SamD20 External Interrupt

geka

Dec 15, 2014
1
Joined
Dec 15, 2014
Messages
1
Hi All,

I am working on a project for my embedded systems class and have been stuck at this section. We are building a 5 floor elevator controlled by the SamD20 (Arm). A 4x4 keypad gives us our inputs, and sends PWM according to the state of the elevator (up or down).

The elevator moves okay but I cannot figure out how to get the board to check for a new input while the elevator is moving. Part of the assignment is to store new inputs and move the elevator to that state after the desired next state has been reached. For example if I am on floor 1, I press floor 3, the elevator starts moving, and I suddenly press 5 while it is moving; I need it to stop at floor 3, and then continue to floor 5. Currently, I can only take a new keypad press AFTER the elevator has stopped moving. Please help!

Here is the condensed read keypad function:

unsigned char read_keypad (void)
{
//establish variables used in the read_keypad function
unsigned char key = 'n';
int row;
//established array used to read keypad
unsigned int keypad_row_bit[4]={PORT_PA22,PORT_PA23,PORT_PA08,PORT_PA09};
//setting a character matrix for the outputs read from keypad
unsigned char keypad_key[4][4]={{'1','2','3','A'},{'4','5','6','B'},{'7','8','9','C'},{'*','0','#','D'}};

...
...

//Checking to see that a button in first row is pressed
PORTA->OUTTGL.reg= PORT_PA10;
for (row=1;row<=4;row++)
{
if (!(PORTA->IN.reg & keypad_row_bit[row-1]))
{
key = keypad_key[0][row-1];
}
}

//Checking to see that a button in second row is pressed
PORTA->OUTTGL.reg=~(PORT_PA10);
PORTA->OUTSET.reg=~(PORT_PA11);
for (row=1;row<=4;row++)
{
if (!(PORTA->IN.reg & keypad_row_bit[row-1]))
{
key = keypad_key[1][row-1];
}
}

//Checking to see that a button in third row is pressed
PORTA->OUTTGL.reg=~(PORT_PA11);
PORTA->OUTSET.reg=~(PORT_PA20);
for (row=1;row<=4;row++)
{
if (!(PORTA->IN.reg & keypad_row_bit[row-1]))
{
key = keypad_key[2][row-1];
}
}
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
Hi there and welcome to Electronics Point :)

Your code was tl;dr but in general, if you can't figure out how to do something "while" you're doing something else, you have to move to some kind of multi-tasking model. There are many approaches.

If you only need two independent tasks, a simple way is to write one of them as a function that includes context and state variables and can be called from inside any other loops in the main code. Every time your main code is waiting for a timer to reach a particular value, you include a call to the function within the loop, and you also call the function at various points during the main code flow. The function does its own thing internaly, and communicates with the main code through some shared variables, or a queue, or whatever is appropriate.

You can use the same technique with more than two tasks if you write all but one task as a callable function with local context and state information. The one task that isn't written like that needs to call the other tasks at appropriate points. It will normally be the most complicated task; the one that ties the other tasks together.

Google state machine for information on how the task functions can be constructed.

Another common arrangement is to use interrupts to trigger execution of the non-mainline tasks. These are again written as self-contained functions with local storage and state information, but instead of being called explicilty by the mainline when it's waiting for things to happen, they are invoked when an interrupt is triggered by an appropriate source. This is often used for serial I/O and in conjunction with a timer for input sampling and/or output updating.

This is a clean way to implement keyboard scanning. Set up an interrupt handler that's triggered by a timer interrupt at a rate of, say, once every 2 ms or so. The interrupt handler reads the data coming back from the keypad rows, updates the outputs that drive the keypad columns, then looks at what the keypad is doing, using current state and context information. It needs to perform debouncing and perhaps other types of processing.

Once it detects a new key being pressed, it might put a code into a queue which would then be processed by the mainline code. Or it might change a variable that the mainline code uses; in this case you need to be careful with the design of your mainline code because that variable could potentially change at any time (it needs to be declared volatile, for a start).

The next step up in complexity is co-operative or pre-emptive multi-tasking, where complete context switches are performed and each task can be written as a simple processing loop. With co-operative multi-tasking, each task voluntarily gives up execution by calling a function normally called defer(). With pre-emptive multi-tasking, deferring is performed under control of a timer interrupt.

Both co-operative and pre-emptive multi-tasking require certain precautions to be taken. Communication between tasks needs to be done carefully, using queues and flags ("semaphores" and "mutex"es) to make sure that invalid combinations of states and data cannot occur. This requirement is more complicated when pre-emptive multi-tasking is used because tasks don't know when a task switch may occur so there is more potential for confusion and unexpected interaction.

If you're using a proper RTOS then multi-tasking is probably built into it; have a look at the manual. If not, it's not too difficult to implement, and the ARM has plenty of resources.

So you need to generalise your code, separate the different types of operations it performs into separate tasks - whichever method you use to give them all execution - and this will make it simpler to design the program flow to support the operations you need to be able to perform simultaneously.

I hope this helps. If not, please post a briefer description of the problem.
 
Top