Debounce code for push-buttons in project

Go To Last Post
103 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello.

 

After performing a couple of searches for debouncing code here in AVR Freaks community  I found this code someone already wrote:

 

/************************************************************************
;*                                                                      *
;*              Testing Read and debounce up to 8 keys                  *
;*              Bulletproof: 4 equal samples needed                     *
;*                                                                      *
;*              Author: P. Dannegger                                    *
;*                                                                      *
;***********************************************************************/
#include 
#include 
#include 

#define KEY_INPUT       PINC
#define LED_OUTPUT      PORTB
#define LED_DIR         DDRB

char key_state;                         // debounced and inverted key state:
                                        // bit = 1: key pressed
char key_press;                         // key press detect


SIGNAL (SIG_OVERFLOW0)
{
  static char ct0, ct1;
  char i;

  i = key_state ^ ~KEY_INPUT;           // key changed ?
  ct0 = ~( ct0 & i );                   // reset or count ct0
  ct1 = ct0 ^ (ct1 & i);                // reset or count ct1
  i &= ct0 & ct1;                       // count until roll over ?
  key_state ^= i;                       // then toggle debounced state
                                        // now debouncing finished
  key_press |= key_state & i;           // 0->1: key press detect
}


char get_key_press( char key_mask )
{
  cli();
  key_mask &= key_press;                // read key(s)
  key_press ^= key_mask;                // clear key(s)
  sei();
  return key_mask;
}


int main( void )
{
  key_state = 0;
  key_press = 0;

  TCCR0 = 1<<CS02;                      //divide by 256 * 256
  TIMSK = 1<<TOIE0;                     //enable timer interrupt

  LED_DIR = 0xFF;
  LED_OUTPUT = 0xFF;
  sei();
  for(;;)                                       // main loop
    LED_OUTPUT ^= get_key_press( 0xFF );        // toggle LEDs on key press
}

 

I'm now trying to integrate this code in my project code but I'm kind of struggling to understand the chronology of events, I mean what happens and when it happens.

 

But first things first.

I'm using an AtMega328P and 2 push-buttons attached at pins PD2 (INT0) and PD3 (INT1) and I'm using their interrupts to perform some actions and I need debouncing routine to ensure only one action per button push.

I'm using avrdude 6.3  under Debian 9 to upload the code into the uC and an USB to TTL UART converter to do the upload.

I'm also aware, from this link, that the name vector for TIMER interrupts have changed and I changed 

SIGNAL (SIG_OVERFLOW0)

to

ISR (TIMER0_OVF_vect)

 

I have also changed register names to match my AtMega328P as follows:

 

TCCR0 = 1<<CS02;

to

TCCR0B = 1<<CS02;

 

and 

TIMSK = 1<<TOIE0;

 

to

TIMSK0 = 1<<TOIE0;

 

I also got rid of the LEDs thing because I don't need them, so summarising, this is what my code looks like:

 

#define KEY_INPUT    PIND

uint8_t key_state = 0;         // debounced and inverted key state:
                               // bit = 1: key pressed
uint8_t key_press = 0;         // key press detect

void get_key_press(uint8_t key_mask){
  cli();
  key_mask &= key_press;                // read key(s)
  key_press ^= key_mask;                // clear key(s)
  sei();
}

void debounce_button_timer_setup(void){
  TCCR0B = 1 << CS02;               //divide by 256 * 256
  TIMSK0 = 1 << TOIE0;              //enable timer interrupt
  sei();
}


debounce_button_timer_setup();
get_key_press(0x0c);

 

This might be a little bit out of context because my project has several files and the code above is in different places, not all together just like I pasted it here.

 

My struggle is that the push buttons are attached at PD2 and PD3 and they are triggering the INT0 and INT1 interrupts and as the debounce code uses TIMERs to raise their flags to run the debounce code, I'm not sure when and where to use the get_key_press() function.

 

I might need to show how my INT0 and INT1 vectors code is:

 

ISR (INT0_vect){
   sweep_sta = SWEEP_STA_UP;
}

ISR (INT1_vect){
   sweep_sta = SWEEP_STA_DOWN;
}

So this is my code for the interrupts 0 and 1 and this sweep_sta variable is being checked inside the main() function infinite loop, so I'm not quite sure where to use the debounce code functions, I mean the get_key_press() function!

Any help is appreciated! I'm sorry if I'm missing any critical information!

 

Thanks

PsySc0rpi0n

This topic has a solution.
Last Edited: Sat. Jul 21, 2018 - 07:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't use the interrupts.

 

Debounce your buttons in the timer routine and check for a debounced button push in your main() routine. If a button is pushed then run your code.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why you suggest not to use interrupts for buttons, I presume?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:
Why you suggest not to use interrupts for buttons, I presume?

Because buttons bounce -- which is why you would use debouncing.

 

Start with Ganssle ... it is interesting and entertaining if nothing else...

http://www.ganssle.com/debouncin...

http://www.ganssle.com/debouncin...

https://pubweb.eng.utah.edu/~cs5...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The only good use of buttons and interrupts is to wake a sleeping mpu.  Otherwise just pole your buttons using the timer overflow interrupt as suggested in the articles linked above.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To be clear, it is fine to use timer interrupts to debounce, you generally don't want the switches themselves to do the interrupting.  

 

Switches generating interrupts can generate a fast lightning storm of them.  To avoid this flood of interrupts, the first one would typically disable further interrupts for some amount of time to prevent the runaway condition. 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Jul 7, 2018 - 02:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the replies.

 

Ok, I think I understand now better the idea of debouncing. I mean, the debouncing routine presented in the code I posted in first post already takes care of the "surveillance" to the button searching for a key press, right?

I never seen this this way. I always thought that the procedure of using interrupts to trigger an action, no matter the way the interrupt was triggered, if with push-buttons or other way, was a complete separate thing the debounce procedure, but now I think that the debounce procedure takes care of the push-button pressing event and also the debounce routine. Am I correct? So, I don't need to trigger an interrupt with the push-button and then perform the debounce routine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You’ve got the idea.

Interrupts are used when you want microsecond responses. Pushbuttons are in the tens of milliseconds. Also, using external interrupts is fraught with danger if you cannot limit the rate they are generated. If the interrupts are generated too frequently, all the processor will be doing is servicing interrupts and everything else grinds to a halt.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok. In my case, these 2 buttons are to increase or decrease the frequency of a signal that is being used in the circuit. So, that situation of the uC being busy only serving interrupts won't be of concern.

Anyway, that will require quite a change in my code. I need to remove the interrupt configuration code and redo it for the TIMER based interrupts! I'm reading the links suggested above!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I have finish reading the following links provided by theusch in post #4.

 

http://www.ganssle.com/debouncin...

http://www.ganssle.com/debouncin...

 

They provide a couple of debounce codes. Now, should I just quit using the code I posted in 1st post and use the ones from those 2 links, or should I try to go with the code I posted in 1st post?

In my case, I think I need 2 pins of the uC because one push-button have different actions from the other one and though I need to differentiate them. I can't have both push-buttons in the same uC pin because I need to know which push-button was pressed. What I mean is that I don't need a code that is able to handle more than one push-button per uC pin. And in this case, I already have push-button 1 on PD2 (hard wired, soldered) and push-button 2 (also hard wired, soldered) to PD3.

 

Does this makes any difference when choosing the code to use?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't quit #1, danni's debounce code is one of the best solutions out there.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Don't quit #1, danni's debounce code is one of the best solutions out there.

 

Ok, I also wanted to go with it.

 

The one I was reading from link 2 doesn't even uses TIMER interrupts. I thought it was using them but apparently not, at least as far as I could understand. In that piece of code, I can't see any configuration of uC TIMER interrupts!

 

Ok, now I need to integrate that code from 1st post into my project code. And I also need help to understand it so that I know where to place each part of the code.

 

So, to start I have a couple of questions. Knowing that I already have each push button attached to PD2 and PD3 with solder (project is already on a stripboard), I will have to send the mask to get_key_pressed() function separately, right? Each one for each push-button, correct? The other question is - is this function, the get_key_press(), that needs to be in a loop to constantly check for the key press or how is it done?

 

I'm still not very into this code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Let me know if I understood it now:

 

get_key_press() function only tells the program in which uC pins to look, right?

 

Then the TIMER routine, checks those pins every time the overflow occurs, is this it?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would suggest that you start by reading this...

https://www.avrfreaks.net/comment/726676#comment-726676

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I have read the walkthrough but it only explains the code inside the ISR routine and the bitwise operations taking place! I can do it on paper when I understand the rest of the code.

 

I need to learn how to integrate this code in my project and for that I need to understand how the code works as a whole!

 

For instance, I need to understand if the get_key_pess() function role is the one I said and if so, how do I arrange the code to deal with a different action to each push-button I have!

 

I mean, if the funciton get_key_press() is only to tell the code which pins of the uC are to be taken into account, how do I then tell the code to perform different actions according to which push-button was pressed!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Direct from danni (Dannegger ):

 

Thats, what the function get_key_press was made for.

You must only give the bitmask of the key, which you want to test and it returns non zero, if the key was pressed.

 

see here:

 

https://www.avrfreaks.net/forum/...

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Direct from danni (Dannegger ):

 

Thats, what the function get_key_press was made for.

You must only give the bitmask of the key, which you want to test and it returns non zero, if the key was pressed.

 

see here:

 

https://www.avrfreaks.net/forum/...

 

 

 

I understand that. My question was rather to confirm (or not) if that function was only to tell the code which pins were to be tested and if it was needed to be used only once or not!

But I think it's now clear it is used only once to tell the code which pins to check.

 

Anyway, in the example code the mask set to get_press_key() is 0xff, meaning that we have 8 pins to be checked. Is this correct? If I want to check only pins PD2 and PD3, the mask needs to be 0x0c, right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:

Anyway, in the example code the mask set to get_press_key() is 0xff, meaning that we have 8 pins to be checked. Is this correct? If I want to check only pins PD2 and PD3, the mask needs to be 0x0c, right?

 

Correct. This code, and many other examples, reads and debounces a whole port, ie all 8 bits, and you then look at individual bits to see what each pin is doing.

 

I often read and debounce all 4 ports (32 bits) in applications as the code, and time, to do it is so small.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:

PsySc0rpi0n wrote:

 

Anyway, in the example code the mask set to get_press_key() is 0xff, meaning that we have 8 pins to be checked. Is this correct? If I want to check only pins PD2 and PD3, the mask needs to be 0x0c, right?

 

Correct. This code, and many other examples, reads and debounces a whole port, ie all 8 bits, and you then look at individual bits to see what each pin is doing.

 

I often read and debounce all 4 ports (32 bits) in applications as the code, and time, to do it is so small.

 

Ok. But I'm trying this code and LED is not changing state.

 

LED is on pin PB1, i.e. pin 15 of my uC and it is always ON. The button is on pin 5, i.e. PD3. Code is as follows:

 

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

#define KEY_INPUT    PIND
#define LED_OUTPUT   PORTB
#define LED_DIR      DDRB

uint8_t key_state = 0;
uint8_t key_press = 0;

uint8_t get_key_press(uint8_t key_mask){
   cli();
   key_mask &= key_press;              //read key(s)
   key_press ^= key_mask;              //clear key(s)
   sei();

   return key_mask;
}

void timer_intr_setup(void){
   TCCR0B = 1 << CS02;                 //divide 256 * 256
   TIMSK0 = 1 << TOIE0;                //enable timer interrupt
}


int main(void){

   timer_intr_setup();

   LED_DIR = 0xff;
   LED_OUTPUT = 0xff;
   sei();
   for(;;){
      LED_OUTPUT ^= get_key_press(0x0c);
   }
}

ISR (TIMER0_OVF_vect){
   static uint8_t ct0, ct1;
   uint8_t i;

   i = key_state ^ ~KEY_INPUT;         //key changed ?
   ct0 = ~(ct0 & i);                   //reset or count ct0
   ct1 = ct0 ^ (ct1 & i);              //reset or count ct1
   i &= ct0 & ct1;                     //count until roll over
   key_state ^= i;                     //thne toggle debounced state
   //now debounce is finished
   key_press |= key_state & i;         //0->1 key press detect
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Describe the wiring. I don't see pull-ups being enabled so I assume you have pull-up/pull-down in the electronics?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Describe the wiring. I don't see pull-ups being enabled so I assume you have pull-up/pull-down in the electronics?

 

Yes, I have a wire that I can change either to PD2 or to PD3 to a 10k ohm resistor that is connected to +5VDC. And from the same pin I have another wire that I use to perform the pull down to ground to simulate the button (I don't have a spare push-button here with me).

 

PD2_____

               /_____10k ohm______+5VDC (PD2 is connected to pull-up resistor)

PD3____ \     |

                     |

                     |

                  GND (wire that I manually drive to gnd to simulate the push-button pressing)

 

 

 

 

PD2_____

               /_____10k ohm______+5VDC (PD3 is connected to pull-up resistor)

PD3____ \    |

                     |

                     |

                     |

                  GND (wire that I manually drive to gnd to simulate the push-button pressing)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So the pins are "active low"? In which case you need to invert your sensing test. Also if they are active low with pull ups why bother with external resistors when the AVR ports already have them for "free"?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
So the pins are "active low"? In which case you need to invert your sensing test.
It's the other way round. Peter's code is for active low, and you have to change it for active high.

 

But there are two volatiles missing. And there is a good chance that get_key_press() got inlined, and then the missing volatiles will definitely harm.

 

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pins PD2 and PD3 are pulled up by external pull up resistors. The wire I have to ground is floating. It only connects to ground when I manually do it. I'm not sure I explained myself correctly! I hope I did.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I have a wire that

Your diagram is a mess (or just drawn wrong)..EACH pin needs a pull up resistor.  The pins are not to be connected together in any manner.   Why do you show them together?   Note that pull ups are built in, so they could be used.

 

Be sure to verify with your meter, the actual pin voltages are going up & down (approx. 5V & 0V).

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are using an ATmega328P then you should ignore all the general advice that applies to all the other types of AVRs and concentrate on Arduino UNO_Arduino Nano library code.   The UNO/Nano Arduino code is specifically for the mega328P and allows the developer to not have to deal with all the low-level hardware aspects of the AVR, such as push-button interfacing.  If you develop for a mega328p using C, then you should do a parallel application project for the Arduino platform.  Because most customers will want the option of having the code in the Arduino code framework if the CPU is a AVR Mega328P.  Using the Arduino platform significantly reduces code maintenance and revision costs, because all the internal operations of the CPU are handled by standardized "plug'n play" libraries.  And because there are many thousands of people who know how to code for Arduino, which means that you don't have to hire specialized expensive embedded-systems engineers for maintenance and revisions.  It doesn't make sense to use a $80/hr engineer for an application that will go into 1 to 100 units of a device running an 80-cent microcontroller.

 

  There are 5 or 6 downloadable libraries for push-switch buttons available.  I use (and have documented) the Alex Brevik library and reviewed the Mat Hertel library.  They both use the 1 millisecond timer0 interrupt that Arduino uses as its internal application code heartbeat.   Both libraries create a class for the push-switch button that compares the status of the button each millisecond to the previous millisecond.

 

  There are four things that an Arduino developer (someone who doesn't have to be concerned about how the actual AVR works on the peripheral register level, and therefore doesn't waste development time on stupid things like switch debouncing) will do with a push button.  One is detect a simple quick ordinary press-and-release.  Two is detect a "double-click", where the button is pressed twice in rapid succession.  Three is a single long press (where the button is held for longer than 0.8 second, and then released).   Four is a long press where the button is held down, and an action happens after each interval of time passes.  An example of this mode is setting the time on a clock where the minutes value will increase every second as long as the "Minutes" button is pressed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

using an ATmega328P then you should ignore all the general advice that applies to all the other types of AVRs

...not have to deal with all the low-level hardware aspects of the AVR...

...someone who doesn't have to be concerned about how the actual AVR works on the peripheral register level, and therefore doesn't waste development time on stupid things

That might be a bit strongly worded. Not sure I'd want the described person designing an airbag control module.  Replacing thinking with canned solutions is not always the right answer.  Of course those are useful tools to thoughtfully reach a solution, while balancing the critical tasks against the repetitive & mundane.  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Yes, I have a wire that

Your diagram is a mess (or just drawn wrong)..EACH pin needs a pull up resistor.  The pins are not to be connected together in any manner.   Why do you show them together?   Note that pull ups are built in, so they could be used.

 

Be sure to verify with your meter, the actual pin voltages are going up & down (approx. 5V & 0V).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:
avrcandies wrote:

Yes, I have a wire that

Your diagram is a mess (or just drawn wrong)..EACH pin needs a pull up resistor.  The pins are not to be connected together in any manner.   Why do you show them together?   Note that pull ups are built in, so they could be used.

 

Be sure to verify with your meter, the actual pin voltages are going up & down (approx. 5V & 0V).

Where did I said PD2 and PD3 were connected together? I never did. They are one close to the other in the AtMega328 uC. Thats why I draw them close to each other, and not to transmit the idea of being connected together.

I just tried to illustrate the wiring I have. Once more:

PD2 and PD3 are supposed to be connected to push-buttons but for this test I don't have spare push-buttons, so I'm simulating them by using a wire to pull them to ground. And each pin PD2 and PD3 have their own pull up resistors (it's not needed I know, but I have them there) and that wire that I'm using to pull PD2 or PD3 to ground to simulate the event of pressing the push-button, is a wire I can remove from PD2 and use it on PD3 or vice versa.

I have already verified with my scope that PD2 and PD3 are being correctly actuated, I mean, when I do nothing, they have 5V, when I use the wire and pull PD2 or PD3 to ground, they go to around 0V.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta, thanks for the insights. However, I'm doing this on the bare AtMega328 only for the fun. I'm not going to produce anything to release on the market. This is for a school project, so the goal is to learn different stuff.
Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:
Where did I said PD2 and PD3 were connected together?
Here...

PD2_____

               /_____10k ohm______+5VDC (PD2 is connected to pull-up resistor)

PD3____ \     |

                     |

                     |

                  GND (wire that I manually drive to gnd to simulate the push-button pressing)

As avrcandies says that sure looks (as drawn) as if PD2 and PD3 are connected to ONE 10K resistor that pulls up to Vcc (+5VDC). He did say:

avrcandies wrote:
(or just drawn wrong).
so I guess it must actually be that. The hope is that you really meant something like....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have a hardware fault.

 

How do I know? Because I took your code and dropped it onto a dev board with correctly wired switches and LEDs and it works. As the only difference is that I am using known good hardware and you are using untested hardware it must be your hardware.

 

 

You can see LED bit 3 on, I can toggle it with switch bit 3.

 

 

 

 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
As the only difference is
Is it? So you are using the same version of the compiler with the same settings?

 

As I already said: there are two volatiles missing in the code. And whether that harms or not, depends on whether the compiler decides to inline get_key_press or not.

 

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:

So you are using the same version of the compiler with the same settings?

 

Ah, of course, he's probably using the brain-dead AVR-GCC whilst I'm using something sensible. wink

 

On a side note....I've never understood why the default action on some compilers is to optimise away variables which aren't volatile. After all, I've made a global variable called 'splat'. I've used a variable called splat in this routine and I've used a variable called splat in that routine. Clearly my intention is that things I write here appear over there. Why optimise it away?

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
Why optimise it away?
The variables are not optimized away, neither in your example nor in the given code here. What is optimized away are memory reads/writes.

Stefan Ernst

Last Edited: Mon. Jul 9, 2018 - 10:56 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:

What is optimized away are memory reads/writes.

 

Does a tree falling in a forest, that no-one hears, make a sound?

 

Does a memory location that is not read or written stop being a variable?

 

devil

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
Does a memory location that is not read or written stop being a variable?
Does "variable" always have to be equal to "memory location"?

 

Edit: And no one said that ALL read/writes are optimized away. In the give code it will only be the ones in the loop.

Stefan Ernst

Last Edited: Mon. Jul 9, 2018 - 11:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've noticed the lack of volatile in Danni's code before now and yet the evidence seems to suggest that it always "works" anyway so there has to be something in the sequence that defeats the compiler's ability to optimize read/writes away. However I do agree that "volatile" would add a certain amount of bullet proofing to that.

Brian Fairchild wrote:
the brain-dead AVR-GCC
How intriguing - so a compiler aggressively optimising (perhaps more so than other compilers) is evidence of "brain death"? I'd have thought it showed superior intelligence - but what do I know?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I've noticed the lack of volatile in Danni's code before now and yet the evidence seems to suggest that it always "works" anyway so there has to be something in the sequence that defeats the compiler's ability to optimize read/writes away.
It "works" in real projects, because very likely get_key_press gets called more than once then. And in a real project there is a good chance that the function itself is in a different compilation unit.

 

In the code here it is a single call in a tight loop with the implementation of the function in the same file, so inlining comes into play and with it the problems because of the missing volatiles.

 

BTW:

char key_state;                         // debounced and inverted key state:
                                        // bit = 1: key pressed
char key_press;                         // key press detect


SIGNAL (SIG_OVERFLOW0)

"char" and "SIGNAL"? It looks like a very early version of the code.

And in newer versions key_state and key_press are volatile.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I've noticed the lack of volatile in Danni's code before now and yet the evidence seems to suggest that it always "works" anyway so there has to be something in the sequence that defeats the compiler's ability to optimize read/writes away.

 

I guess what we need is for someone to drop the code in post #19 into AVRGCC and see what gets produced. 

 

clawson wrote:

...so a compiler aggressively optimising (perhaps more so than other compilers) is evidence of "brain death"? I'd have thought it showed superior intelligence - but what do I know?

 

Surely a smart compiler would know that a variable used in an ISR is going to be used elsewhere and not optimise it, or the access to it, away - but, like you, what do I know? wink

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
Surely a smart compiler would know that a variable used in an ISR is going to be used elsewhere and not optimise it
How can it know? It could be (and very likely is) in a different compilation unit.

 

@Stefan, the "master copy" of Danni's debounce code is surely?....

 

https://community.atmel.com/proj...

 

no sign of "volatile" in that.

Last Edited: Mon. Jul 9, 2018 - 12:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

How can it know? It could be (and very likely is) in a different compilation unit.

 

 

I have never delved into GCC's internals but I'd have thought...

 

1) It knows what an ISR is as it generates a different prologue/epilogue.

2) It must flag variable 'types' across different compilation units anyways to identify size mismatches.

 

Given that, I don't see a reason why it couldn't, when encountering a variable being used in an ISR, flag it as such for later interpretation in other units.

 

It might be that it's just not possible to do. I know that GCC is very processor agnostic at the front end and it might be that the necessary information to make smarter microcontroller-friendly decisions doesn't get carried across to the lower level processor specific parts.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
@Stefan, the "master copy" of Danni's debounce code is surely?....

https://community.atmel.com/proj...

no sign of "volatile" in that.

I didn't know that he didn't update his code here on AVRFreaks.

 

His latest version (at least I think it is) can be found here:

https://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29

(it includes detection of short, long, and repeated key presses)

 

Edit: "repeated key presses" in conjunction with "detection" is misleading.

It provides an auto-repeat for long presses.

Stefan Ernst

Last Edited: Mon. Jul 9, 2018 - 01:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Anyways....

 

 

although I don't use it I do have a copy of Studio 6.2 installed. So I took the code from post #19, changed the ports used, dropped it into Studio and compiled it.

 

Guess what? It works without any mention of 'volatile'.

 

 

For reference, my build window...

 

 

Quote:

------ Build started: Project: GccApplication2, Configuration: Debug AVR ------

Build started.

Project "GccApplication2.cproj" (default targets):

Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').

Target "CoreBuild" in file "C:\Program Files\Atmel\Atmel Studio 6.2\Vs\Compiler.targets" from project "D:\Documents\Atmel Studio\6.2\GccApplication2\GccApplication2\GccApplication2.cproj" (target "Build" depends on it):

Using "RunCompilerTask" task from assembly "C:\Program Files\Atmel\Atmel Studio 6.2\Extensions\Application\AvrGCC.dll".

Task "RunCompilerTask"

Shell Utils Path C:\Program Files\Atmel\Atmel Studio 6.2\shellUtils

C:\Program Files\Atmel\Atmel Studio 6.2\shellUtils\make.exe all 

Building file: .././GccApplication2.c

Invoking: AVR/GNU C Compiler : 4.8.1

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-gcc.exe"  -x c -funsigned-char -funsigned-bitfields -DDEBUG  -O1 -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -mrelax -g2 -Wall -mmcu=atmega1284p -c -std=gnu99 -MD -MP -MF "GccApplication2.d" -MT"GccApplication2.d" -MT"GccApplication2.o"   -o "GccApplication2.o" ".././GccApplication2.c" 

In file included from .././GccApplication2.c:3:0:

c:\program files\atmel\atmel toolchain\avr8 gcc\native\3.4.1061\avr8-gnu-toolchain\avr\include\util\delay.h(90,3): warning: #warning "F_CPU not defined for <util/delay.h>" [-Wcpp]

# warning "F_CPU not defined for <util/delay.h>"

   ^

Finished building: .././GccApplication2.c

Building target: GccApplication2.elf

Invoking: AVR/GNU Linker : 4.8.1

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-gcc.exe" -o GccApplication2.elf  GccApplication2.o   -Wl,-Map="GccApplication2.map" -Wl,--start-group -Wl,-lm  -Wl,--end-group -Wl,--gc-sections -mrelax -mmcu=atmega1284p  

Finished building target: GccApplication2.elf

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures  "GccApplication2.elf" "GccApplication2.hex"

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-objcopy.exe" -j .eeprom  --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0  --no-change-warnings -O ihex "GccApplication2.elf" "GccApplication2.eep" || exit 0

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-objdump.exe" -h -S "GccApplication2.elf" > "GccApplication2.lss"

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-objcopy.exe" -O srec -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures "GccApplication2.elf" "GccApplication2.srec"

"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-size.exe" "GccApplication2.elf"

   text    data     bss     dec     hex filename

    324       0       4     328     148 GccApplication2.elf

Done executing task "RunCompilerTask".

Using "RunOutputFileVerifyTask" task from assembly "C:\Program Files\Atmel\Atmel Studio 6.2\Extensions\Application\AvrGCC.dll".

Task "RunOutputFileVerifyTask"

Program Memory Usage : 324 bytes   0.2 % Full

Data Memory Usage : 4 bytes   0.0 % Full

Done executing task "RunOutputFileVerifyTask".

Done building target "CoreBuild" in project "GccApplication2.cproj".

Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != '').

Target "Build" in file "C:\Program Files\Atmel\Atmel Studio 6.2\Vs\Avr.common.targets" from project "D:\Documents\Atmel Studio\6.2\GccApplication2\GccApplication2\GccApplication2.cproj" (entry point):

Done building target "Build" in project "GccApplication2.cproj".

Done building project "GccApplication2.cproj".

 

Build succeeded.

========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Brian Fairchild wrote:
Guess what? It works without any mention of 'volatile'.
I don't get it.

Do you really think that a test with a random (old) compiler version (4.8.1) and a random optimizer setting (-O1) does proof anything?

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:

Do you really think that a test with a random (old) compiler version (4.8.1) and a random optimizer setting (-O1) does proof anything?

 

 

Instead of sitting there at your keyboard picking holes in people's attempt to help why don't you offer some proof.

 

 

Oh, and I've tried every optimisation setting from -O0 to -O3 and all of them work.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

Last Edited: Mon. Jul 9, 2018 - 02:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian,

 

Stefan is right. GCC is a fiercely optimising compiler. If not today then tomorrow with a different issue of the compiler or just some small change in one of its 100's of command line switches this code will prove dangerous. It is the programmer's responsibility to make known to the compiler anything that is shared between paths of execution and that is done using "volatile". By some complete fluke it may appear to work in one build with one issue of the compiler and one set of build switches but it's going to bite one day unless it's done properly and for GCC that means making shared items volatile. It's so important that it's been FAQ entry #1 in the GCC manual almost right from the start:

 

http://nongnu.org/avr-libc/user-...

 

and by the same token it's been the #1 issue in my signature for a decade or more for the same reason. It's fundamental to the use of avr-gcc and is one of the most common reasons for "it's not working" threads here on Freaks that involve GCC.

Last Edited: Mon. Jul 9, 2018 - 03:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian:

Because I took your code and dropped it onto a dev board

That is a nice board...Is it available somewhere??...reminds me of my favorite, defunct, STK500. 

 

https://youtu.be/89g1P_J40JA?t=179

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Stefan is right. GCC is a fiercely optimising compiler. ...

 

It'll be interesting if (when?) the OP posts either the .LSS so we can see what's being generated or at least tells us the toolchain they are using. They were using...

 

Quote:

I'm using Atmel AVR 8-bit Toolchain 3.5.4 - Linux 64-bit which includes avr-gcc-4.8.1.

 

...I guess until then it's all speculation.

 

 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

That is a nice board...Is it available somewhere??...reminds me of my favorite, defunct, STK500. 

 

Kanda STK200X.

 

It's my go-to board for testing out code on real hardware. 8 push buttons which can be jumped onto any port. The same with 8 LEDs. Takes just about any DIP AVR and has an onboard FTDI USB USART which comes in handy as a debug channel. And an LCD connector.

 

I made one mod, which can be seen in the picture, in that I remove the soldered in crystal and put in a chopped-up IC socket to allow my to change the oscillator frequency.

 

It is more expensive than an Arudino but it's way more useful as a bench top unit. I was thinking earlier today that I might get a couple more. They are normally sold as a kit with programmer etc but I have bought just the board from Kanda before now.

 

 

Here is the user manual.

Attachment(s): 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello... I've been reading the latest posts, and to be honest, it's completely out of my (nearly none) comfort zone! So, can I provide anything from my compilation log or anything you need to help you guys in the discussion that is happening? Let me know and I'll paste here or somewhere else.

 

Anyway, about the original post.

 

I might have mislead my idea when I tried to explain my wiring. I'll try again.

 

So, I have just picked up a spare AtMega328p, placed it on a breadboard along with the crystal and caps and all the basic stuff needed to make it work.

Then, as I don't have spare push-buttons for the reset and for the testing I wanted to do, what I did was to place one of the leads of a 10k ohm pull-up resistor connected to +5VDC line. The other lead of this resistor is somewhere on the bredboard not connected to anything. Then I used a wire to connect this lead of the 10k ohm resistor to one of the 2 pins, PD2 or PD3.

 

PD2\

       \

         \_____10k ohm_____+5VDC

          .

         .

       .

PD3.

 

So, what I wanted to say here is that the thing in red is a wire I can disconnect from PD2 and connect to PD3 just to be able to make the test to the 2 pins with only 1x 10k ohm resistor, instead of having 2x 10k ohm resistor, 1 for each pin.

 

And adding to that drawing I have another wire going from the left lead of the 10k ohm resistor (the one in red) to ground when I want to manually simulate the event of pressing the push-button.

I'm really sorry if my drawing was (is still) poor, but it's the best I can think of to represent what I have on the breadboard.

 

About the code compilation, yes, I'm using Debian 9 repository avr-gcc (GCC) 4.9.2 from within a makefile I downloaded somewhere from the internet. I can also upload the makefile if needed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By having the inputs floating, the results will be indeterminate. Either put a 10k resistor to 5V on each of the inputs or enable the internal pullups. To activate the ‘switch’, connect the required port pin to 0V.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't get it yet.  able to make the test to the 2 pins with only 1x 10k ohm resistor, instead of having 2x 10k ohm resistor, 1 for each pin.

 

Why do you keep talking about & showing only one resistor?  Does your setup match the correct drawing given by Clawson?

 

There must be TWO resistors, one going from 5v to PD2, and another resistor going from 5V to PD3.  It really can't be any simpler (other than using the built-in pullups)...It is better to add your own for now, since you are sure they are taking effect.  The built-ins, require your software to be correct in order to activate those.

 

You can use wires to gnd to pull either or both pins to gnd as desired (or get some switches).  Why are you messing with debouncing switches, when you don't have any (just wondering)? 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman already understood what I was trying to say. And I already understood you you all are saying. And I'll make the changes to match what I need to have.

avrcandies, I was talking and showing what I had in hardware because it was what I had in hardware in fact. Ok, its not correct, but it was what I had, ok? Got it? My mistake might only be to have one of the 2 pins floating when I shouldn't and I'll fix that later today, but that was what I had on the breadboard.
And I've already ordered a complete set of several different push-button from eBay, but they will take quite a while to arrive, so as we use to say around "if you don't have a dog, you'll have to hunt with a cat..."

Later today, after work ill be back to my tests.
Thanks

Last Edited: Tue. Jul 10, 2018 - 06:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's good that your are fixing up your setup...having real switches will make checking things out a lot better.  Things may start off rocky, but you'll get there step-by-step.   Keep experimenting and live the dream! 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are four possible causes for your problems...

 

1) Hardware Design - what your hardware should look like

2) Hardware Implementation - what you actually built, including any faults

3) Software Design - the algorithm used

4) Software Implementation - What the compiler outputs

 

It sounds like 1) is sorted when you follow the advice given above. We know 3) is OK because I've used your exact code and it works on my board here. So that leaves 2) or 4).

 

With regards to 4) there has been some discussion about the use of 'volatile'. I have proved that on one version of the compiler it doesn't matter. On other versions it might (although there is a different argument about whether that behavior is correct).

 

To help eliminate 4), and hence prove your problem lies with 2) could you...

 

a) compile the non-working code as you posted back in post #19

b) find the .LSS file generated

c) copy and paste the whole .LSS file into this topic

 

Thanks.

 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello.

Sorry for the late reply.

Today was a rough day. My only spare time was last 10 minutes I took to add an extra 10k ohm resistor to PD3 (PD2 already had one) and try to load the code again and test. LED is always ON even so!

 

I couldn't do any more testing and I'm about to go to bed. Just time to tell the files I have after compilation:

debounce.srec

debounce.o

debounce.map

debounce.lst

debounce.hex

debounce.elf

debounce.c

debounce.bin

debounce_eeprom.srec

debounce_eeprom.hex

debounce_eeprom.bin

 

no .LSS file.

 

Let me know what else you need. I had no time to perform all the other fail safe checks that Brain told me! Tomorrow I'll try to re-check wirings and hardware and paste here compilation output if needed, and also my Makefile!

 

Thanks

Psy

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Hello, 

   I suggest that instead of learning to understand the Mega328P AVR microcontroller as a device, learn instead how to interface simple and cheap module boards to the Mega328P that is the key component of the Arduino system.  I suggest thinking of the Arduino UNO or Nano as the lowest level of hardware that you should spend time learning.  Instead, learn I2C {TWI in Atmel language, Wire.h in Arduino language} by connecting a cheap DS3231 clock module to the AVR (on the standardized single-board hardware development platform, the Arduino).  Get an LCD 16x2 char display or a ST7735 TFT 160x128 SPI display and add it to the system.  Download the libraries for Arduino in GitHub for these parts.  Study the code.  This is the place where everybody tries to show that Arduino is not a toy by using every academic trick that they learned in C++ programming school in the library application that they are offering.  So you will get a crash, "sink or swim" course in C++ coding.  Most of the time, when you have the hardware connected correctly, and the example code will compile correctly, then your application /.ino /sketch/program/ will run its demo correctly.  Even if you are not exactly sure what is happening, or what the data that you are receiving means.

 

  Other cheap interesting interface-module boards on eBay are the RDA5807M FM-radio receiver,  the INA219 I2C voltage/amp meter, the AD9833 Sine/Triangle/Square programmable function generator,  the DFPlayer MP3 module that reads music directly from SD chip/cards, the VS1053 MP3 player/Ogg recorder/MIDI tone module audio-processor board, the compass-gyro-accelemeter MEMS ICs. 

 

  It's better to learn CPU to peripheral interfacing and user-interaction systems than it is to learn the internals of an individual processor.

  My two cents worth.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

debounce.lst will do just fine thankyou.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
debounce.lst will do just fine thankyou.
Err no - it's unlinked. It's the LSS that is created by an "objdump -S" from the ELF that is more useful. As7 has a tick box somewhere in the project setting to say "and create an LSS". I though this was enabled by default but I guess OP must have disabled it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Err no - it's unlinked. It's the LSS that is created by an "objdump -S" from the ELF that is more useful. As7 has a tick box somewhere in the project setting to say "and create an LSS". I though this was enabled by default but I guess OP must have disabled it.

 

Thanks. So, @OP, it's the .LSS we want.

 

(boy, you GCC types have it tough, so many hoops to jump through and options to set. wink)

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
(boy, you GCC types have it tough, so many hoops to jump through and options to set.
And yet that is why most of us love GCC as it has literally hundreds of options which mean you can get it to do pretty much anything you ever hoped to achieve with a compiler. In fact GC+binutils have grown organically with 10,000's of programmers, each with their own requirements, saying "if only the compiler/linker could do this too" so each one adds the feature they are looking for and as long as it's considered an attractive feature to have and is implemented without obvious bugs the core team permit these things to be added making GCC perhaps the most configurable compiler/linker toolchain you can use. This is the joy of FOSS software!

 

Of course the downside is that there are myriad options and a beginner does not know which are the vital "must have" things and which are some esoteric mind trip only of use to some Icelandic code hacker on every third Thursday in July. Take optimisation for instance. Some compilers just have "on / off" or "on / mild / aggressive" and while GCC does have "grouping" options such as -O0, -O1, -O2, -O3, -Os, -Og these are just picking 10 or 20 or 30 options to be applied all at once. But every last optimisation option is individually switchable:

 

https://gcc.gnu.org/onlinedocs/g...

 

That page documents just the options to control optimization in GCC and that page is 1,900 lines long!! It can take a lifetime's work to study and understand every last option that GCC offers (I learn something new at least once a week if not once a day!) so yeah, I guess that could be considered "jumping through hoops". But personally I wouldn't have it any other way.

 

(I first started to use GCC for ARM projects in the early 90's - almost 30 years later and I'm still learning!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello.

 

Which then is the option to enable the creation of these .LSS files? I have -Os enabled in my Makefile.

 

 

Edited;

 

I have this in my Makefile:

 

%.lst: %.elf
	$(OBJDUMP) -h -S $< > $@

 

So, maybe the .LSS file you're looking for is probably with the same content as my actual .lst, no?

Last Edited: Thu. Jul 12, 2018 - 08:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, beyond the fact that I was using active-low (resistor from pin to +5VDC and wire to short to GND when I wanted something to happen), I already reversed this situation and connected PD2 and PD3 to GND through 2 10k ohm resistors and used a wire to touch +5VDC to make the LED to switch state, but still not happening.

 

Here is .LSS file content:

 


debounce.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000000  00800100  00000130  000001c4  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         00000130  00000000  00000000  00000094  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .bss          00000004  00800100  00800100  000001c4  2**0
                  ALLOC
  3 .stab         000006c0  00000000  00000000  000001c4  2**2
                  CONTENTS, READONLY, DEBUGGING
  4 .stabstr      00000cc3  00000000  00000000  00000884  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .comment      00000011  00000000  00000000  00001547  2**0
                  CONTENTS, READONLY
  6 .note.gnu.avr.deviceinfo 00000040  00000000  00000000  00001558  2**2
                  CONTENTS, READONLY

Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 34 00 	jmp	0x68	; 0x68 <__ctors_end>
   4:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
   8:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
   c:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  10:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  14:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  18:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  1c:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  20:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  24:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  28:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  2c:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  30:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  34:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  38:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  3c:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  40:	0c 94 59 00 	jmp	0xb2	; 0xb2 <__vector_16>
  44:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  48:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  4c:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  50:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  54:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  58:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  5c:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  60:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>
  64:	0c 94 46 00 	jmp	0x8c	; 0x8c <__bad_interrupt>

00000068 <__ctors_end>:
  68:	11 24       	eor	r1, r1
  6a:	1f be       	out	0x3f, r1	; 63
  6c:	cf ef       	ldi	r28, 0xFF	; 255
  6e:	d8 e0       	ldi	r29, 0x08	; 8
  70:	de bf       	out	0x3e, r29	; 62
  72:	cd bf       	out	0x3d, r28	; 61

00000074 <__do_clear_bss>:
  74:	21 e0       	ldi	r18, 0x01	; 1
  76:	a0 e0       	ldi	r26, 0x00	; 0
  78:	b1 e0       	ldi	r27, 0x01	; 1
  7a:	01 c0       	rjmp	.+2      	; 0x7e <.do_clear_bss_start>

0000007c <.do_clear_bss_loop>:
  7c:	1d 92       	st	X+, r1

0000007e <.do_clear_bss_start>:
  7e:	a4 30       	cpi	r26, 0x04	; 4
  80:	b2 07       	cpc	r27, r18
  82:	e1 f7       	brne	.-8      	; 0x7c <.do_clear_bss_loop>
  84:	0e 94 89 00 	call	0x112	; 0x112 <main>
  88:	0c 94 96 00 	jmp	0x12c	; 0x12c <_exit>

0000008c <__bad_interrupt>:
  8c:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>

00000090 <get_key_press>:

volatile uint8_t key_state = 0;
volatile uint8_t key_press = 0;

uint8_t get_key_press(uint8_t key_mask){
   cli();
  90:	f8 94       	cli
   key_mask &= key_press;              //read key(s)
  92:	90 91 00 01 	lds	r25, 0x0100	; 0x800100 <_edata>
  96:	89 23       	and	r24, r25
   key_press ^= key_mask;              //clear key(s)
  98:	90 91 00 01 	lds	r25, 0x0100	; 0x800100 <_edata>
  9c:	98 27       	eor	r25, r24
  9e:	90 93 00 01 	sts	0x0100, r25	; 0x800100 <_edata>
   sei();
  a2:	78 94       	sei

   return key_mask;
}
  a4:	08 95       	ret

000000a6 <timer_intr_setup>:

void timer_intr_setup(void){
   TCCR0B = 1 << CS02;                 //divide 256 * 256
  a6:	84 e0       	ldi	r24, 0x04	; 4
  a8:	85 bd       	out	0x25, r24	; 37
   TIMSK0 = 1 << TOIE0;                //enable timer interrupt
  aa:	81 e0       	ldi	r24, 0x01	; 1
  ac:	80 93 6e 00 	sts	0x006E, r24	; 0x80006e <__TEXT_REGION_LENGTH__+0x7e006e>
  b0:	08 95       	ret

000000b2 <__vector_16>:
  b2:	1f 92       	push	r1
  b4:	0f 92       	push	r0
  b6:	0f b6       	in	r0, 0x3f	; 63
  b8:	0f 92       	push	r0
  ba:	11 24       	eor	r1, r1
  bc:	2f 93       	push	r18
  be:	8f 93       	push	r24
  c0:	9f 93       	push	r25
  c2:	90 91 01 01 	lds	r25, 0x0101	; 0x800101 <key_state>
  c6:	29 b1       	in	r18, 0x09	; 9
  c8:	20 95       	com	r18
  ca:	29 27       	eor	r18, r25
  cc:	80 91 03 01 	lds	r24, 0x0103	; 0x800103 <ct0.1657>
  d0:	82 23       	and	r24, r18
  d2:	80 95       	com	r24
  d4:	80 93 03 01 	sts	0x0103, r24	; 0x800103 <ct0.1657>
  d8:	90 91 02 01 	lds	r25, 0x0102	; 0x800102 <ct1.1658>
  dc:	92 23       	and	r25, r18
  de:	98 27       	eor	r25, r24
  e0:	90 93 02 01 	sts	0x0102, r25	; 0x800102 <ct1.1658>
  e4:	82 23       	and	r24, r18
  e6:	89 23       	and	r24, r25
  e8:	90 91 01 01 	lds	r25, 0x0101	; 0x800101 <key_state>
  ec:	98 27       	eor	r25, r24
  ee:	90 93 01 01 	sts	0x0101, r25	; 0x800101 <key_state>
  f2:	20 91 01 01 	lds	r18, 0x0101	; 0x800101 <key_state>
  f6:	90 91 00 01 	lds	r25, 0x0100	; 0x800100 <_edata>
  fa:	82 23       	and	r24, r18
  fc:	89 2b       	or	r24, r25
  fe:	80 93 00 01 	sts	0x0100, r24	; 0x800100 <_edata>
 102:	9f 91       	pop	r25
 104:	8f 91       	pop	r24
 106:	2f 91       	pop	r18
 108:	0f 90       	pop	r0
 10a:	0f be       	out	0x3f, r0	; 63
 10c:	0f 90       	pop	r0
 10e:	1f 90       	pop	r1
 110:	18 95       	reti

00000112 <main>:
}


int main(void){

   timer_intr_setup();
 112:	0e 94 53 00 	call	0xa6	; 0xa6 <timer_intr_setup>

   LED_DIR = 0xff;
 116:	8f ef       	ldi	r24, 0xFF	; 255
 118:	84 b9       	out	0x04, r24	; 4
   LED_OUTPUT = 0xff;
 11a:	85 b9       	out	0x05, r24	; 5
   sei();
 11c:	78 94       	sei
   for(;;){
      LED_OUTPUT ^= get_key_press(0x0c);
 11e:	8c e0       	ldi	r24, 0x0C	; 12
 120:	0e 94 48 00 	call	0x90	; 0x90 <get_key_press>
 124:	95 b1       	in	r25, 0x05	; 5
 126:	89 27       	eor	r24, r25
 128:	85 b9       	out	0x05, r24	; 5
   }
 12a:	f9 cf       	rjmp	.-14     	; 0x11e <main+0xc>

0000012c <_exit>:
 12c:	f8 94       	cli

0000012e <__stop_program>:
 12e:	ff cf       	rjmp	.-2      	; 0x12e <__stop_program>

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok so what do you expect to happen? What actually happens?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, as I remember that someone said here these 2 pins, PD2 and PD3, should be active-high for this code, I connected both 10k ohm resistors, each one from each pin to GND and I'm using a wire to short either of these 2 pins to +5VDC and I was expecting to see LED going ON/OFF but LED is always ON.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What do you mean LED?  Shouldn't you have two of them?  How would two switches control an LED (maybe if either is pressed, then light the led).

 

Debouncing is pretty straightforward, not sure why you're messing around so much.

 

Make it easy:

set up a timer irq that fires 200 times a sec

in the irq check switch A, if it is pressed:

   increment countA, limit the count to 40 max

else decrement countA, don't let it go below zero

 

Do the same thing for switch B (countB)

 

===============

in your main code  if countA is > 20 then the switch is pressed & do what you want

likewise for B

 

You can write this in 15 minutes and be done.  That's as dirt-quick as it gets & works GRRRRRRREAT.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, but I'll be reading a bit about the timer thing in the datasheet, so I might take longer. I don't know how to set the time I want the overflow to occur (1/200 of a sec), so I need to read to see if I can figure it out!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here fellow freak; this gives you everything you need for the timer0 setup

 

http://maxembedded.com/2011/07/avr-timers-ctc-mode/

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Here fellow freak; this gives you everything you need for the timer0 setup

 

http://maxembedded.com/2011/07/avr-timers-ctc-mode/

 

 

 

That was one of the resources I was reading, thank you! :)

Last Edited: Sat. Jul 14, 2018 - 07:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:

Here is .LSS file content:...

 

Well, unless I've missed something, the lack of 'volatile' is not the cause of your problems here.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Debouncing is pretty straightforward, not sure why you're messing around so much.

 

It is, and the code the OP posted back in #19 works.

 

And it works for either active-high or active-low inputs. (Think about it, we debounce both rising and falling edges of a switch closing/opening. The software does not care what the inactive state of the switch is. It's only when we come to interpret the result that it matters).

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@OP  can you post the .hex file and I'll run it on known working hardware.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, to clear things out:

 

Does it matters if I'm using active-low or active high in PD2 and PD3 or not?

 

Either ways, .hex file content is this:

 

:100000000C9434000C9446000C9446000C9446006A
:100010000C9446000C9446000C9446000C94460048
:100020000C9446000C9446000C9446000C94460038
:100030000C9446000C9446000C9446000C94460028
:100040000C9457000C9446000C9446000C94460007
:100050000C9446000C9446000C9446000C94460008
:100060000C9446000C94460011241FBECFEFD8E03C
:10007000DEBFCDBF21E0A0E0B1E001C01D92A43001
:10008000B207E1F70E9487000C9494000C940000E2
:10009000F894909100018923982790930001789417
:1000A000089584E085BD81E080936E0008951F92DD
:1000B0000F920FB60F9211242F933F938F939F931C
:1000C0003091010129B120952327809103018223DA
:1000D0008095809303019091020192239827909339
:1000E00002012823822F8923982F932790930101BF
:1000F000892390910001892B809300019F918F911A
:100100003F912F910F900FBE0F901F9018950E9456
:1001100051008FEF84B985B978948CE00E94480033
:0C01200095B1892785B9F9CFF894FFCF7D
:00000001FF

 

And I was now testing a code made by myself, trying to follow post #67 suggestions from avrcandies.

 

//Datasheet used
//http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega328_P%20AVR%20MCU%20with%20picoPower%20Technology%20Data%20Sheet%2040001984A.pdf

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

#define COUNT 20

volatile uint8_t counter = 0;

int main(void){

   DDRB = 0xff;


   //Using Timer1, page 152
   //Prescaler to be used, if needed, Table 20-7, page 177
   TCCR1B = (1 << CS11); //prescaler of 8

   //Operation mode, Table 20-6, pages 175 and 176
   TCCR1A = (1 << WGM11) | (1 << WGM10); //set mode to Fast PWM, triggering interrupt at TOP value of OCR1A
   TCCR1B = (1 << WGM13) | (1 << WGM12); //meaning all WGM1[3:0] bits set

   //Register that will contain the value to be compared with
   OCR1A = 10000; //10k counts according to prescaler of 8 for 5ms delay, 5ms / (1/(16Mhz/8)) = 10k counts

   TIMSK1 = 1 << OCIE1A;
   sei();

   for(;;){
      if(counter == COUNT)
         PORTB ^= (1 << PB1);
   }
   return 0;
}

ISR(TIMER1_COMPA_vect){
   if(!(PIND & (1 << PD2))){
      if( (++counter >= COUNT) || (counter < 0) )
         counter = 0;
   }else{
      counter--;
   }
}

 

But still not working either!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How can counter be less than 0? You can simplify your logic by using a downcounter. If he pin is high, then counter = COUNT else if counter > 0 then counter—

If counter equal 0 then the pin has been sampled as low for COUNT times. Simples.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
How can counter be less than 0? You can simplify your logic by using a downcounter. If he pin is high, then counter = COUNT else if counter > 0 then counter— If counter equal 0 then the pin has been sampled as low for COUNT times. Simples.

 

A variable can contain sign or not, right? That's why there are signed and unsigned types of variables. Despite of that I just tried to follow avrcandies instructions and he said specifically to not let it go under 0.

 

I think I found a bug on my test program. I used in main() "if counter == COUNT" and maybe I should use '>' instead of '=='.

 

I'm sorry that I'm changing what I'm trying to do but I'm following suggestions and some of you says to do "this" and others says to do "that" and this might become a bit messy but I?ll try to follow up!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:

Either ways, .hex file content is this:

 

Thankyou.

 

 

PsySc0rpi0n wrote:

But still not working either!

 

OK, so I take your hex file posted above and use it to program a 328P sitting in a known working test PCB (the one I posted a picture of earlier). The PCB uses active low switches and active low LEDs. I make NO changes to the file at all.

 

IT WORKS!

 

If I press the switch connected to PortD.2 it toggles on and off the LED connected to PortB.4. If I press the switch on PortD.3 the LED on B.5 toggles. 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:

PsySc0rpi0n wrote:

Either ways, .hex file content is this:

 

Thankyou.

 

 

PsySc0rpi0n wrote:

But still not working either!

 

OK, so I take your hex file posted above and use it to program a 328P sitting in a known working test PCB (the one I posted a picture of earlier). The PCB uses active low switches and active low LEDs. I make NO changes to the file at all.

 

IT WORKS!

 

If I press the switch connected to PortD.2 it toggles on and off the LED connected to PortB.4. If I press the switch on PortD.3 the LED on B.5 toggles. 

 

Why you are talking about PortB.4 and PortB.5? I thought it was PB1 or PortB.1. That's what I have in my code.

 

Edited;

Ah ok, I think any PortB pin should work as it was the whole port set as output!

Last Edited: Sat. Jul 14, 2018 - 01:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:

Why you are talking about PortB.4 and PortB.5? I thought it was PB1 or PortB.1. That's what I have in my code.

 

My bad, I had the jumper cable off by a row. It's actually PortB.2 and Port B.3 (pins 16 and 17 on the chip)

 

I think you misunderstand the return value from get_key_press(). It returns a bit mask of which keys are pressed within your mask value. So if you send 0x0C to it, it will look at bits/switches 2 and 3 and return the state of those switches, once debounced, in bits 2 and 3.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:

PsySc0rpi0n wrote:

Why you are talking about PortB.4 and PortB.5? I thought it was PB1 or PortB.1. That's what I have in my code.

 

My bad, I had the jumper cable off by a row. It's actually PortB.2 and Port B.3 (pins 16 and 17 on the chip)

 

I think you misunderstand the return value from get_key_press(). It returns a bit mask of which keys are pressed within your mask value. So if you send 0x0C to it, it will look at bits/switches 2 and 3 and return the state of those switches, once debounced, in bits 2 and 3.

 

Regardless of that, the code is still not working here! But I'm at the moment trying to do what avrcandies said!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quit using concatenated logic, keep it simple & do one thing at a time--not 5 things in one statement!

 

if (pind & (1<<PD2))  {
    if (counter<COUNT)
       counter++;
    }

else

   if (counter>0)
      counter--;

In main DO NOT check for =  check for >=...the count will be increasing rapidly & you will miss the exact matching  & wonder why you never get a hit.

You must pick a check that is perhaps halfway to the max limit  (COUNT/2)  ..NOT the max, or you will lose holding debounce protection (like when you have a weak finger)

 

Simple Summary: 

When the button not pushed, counts down to zero limit

When the button is pushed, counts up to MAX limit

When the count>= MAX/2 , you have a valid press....easy??   

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Jul 14, 2018 - 08:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also I'd reduce it to one button not two for starters so not 0x0C but a mask with just one bit set until you understand it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PsySc0rpi0n wrote:
Regardless of that, the code is still not working here!

So your code works here on my known working good hardware but not on your hardware. What does that suggest?

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, still about avrcandies suggestion, I made the code to work but I didn't understood something.

 

The code is as follows:

 

//Datasheet used
//http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega328_P%20AVR%20MCU%20with%20picoPower%20Technology%20Data%20Sheet%2040001984A.pdf

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

#define COUNT 100

volatile uint8_t counter = 0;

int main(void){

   DDRB = 0xff;


   //Using Timer1, page 152
   //Prescaler to be used, if needed, Table 20-7, page 177
   TCCR1B = (1 << CS11); //prescaler of 8

   //Operation mode, Table 20-6, pages 175 and 176
   //set mode to CTC, TOP value of OCR1A, WGM1[3:0] -> 0100
   TCCR1A &= ~((1 << WGM11) | (1 << WGM10)); // WGM11 and WGM10 unset
   TCCR1B |= (1 << WGM12);   // WGM12 set
   TCCR1B &= ~(1 << WGM13 ); // WGM13 unset

   //Register that will contain the value to be compared with
   OCR1A = 10000; //10k counts according to prescaler of 8 for 5ms (200Hz) delay, 5ms / (1/(16Mhz/8)) = 10k counts

   //Enable Compare Output A mode
   TIMSK1 = (1 << OCIE1A);

   for(;;){
      if(TCNT1 & (1 << 12))
         PORTB = (1 << PB1);
      else
         PORTB = 0;
   }
   return 0;
}

 

What I didn't understood is why I had to read bit 12 of TCNT1 to get the 200Hz on the scope. I did this by trial and error!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
PsySc0rpi0n wrote:
Regardless of that, the code is still not working here!
So your code works here on my known working good hardware but not on your hardware. What does that suggest?

 

My hardware is working with other codes! I have no idea why that code is not working here! But yes, it suggests my hardware is probably not matching the code. I wonder why!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, apparently it's not reasonable to try to do that.

 

Anyway, I made it working for 200Hz using interrupts. Here is the code:

 

//Datasheet used
//http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega328_P%20AVR%20MCU%20with%20picoPower%20Technology%20Data%20Sheet%2040001984A.pdf

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

#define COUNT 100

volatile uint8_t counter = 0;

int main(void){

   DDRB = 0xff;

   //Using Timer1, page 152
   //Prescaler to be used, if needed, Table 20-7, page 177
   TCCR1B = (1 << CS11) | (1 << CS10); //prescaler of 64

   //Operation mode, Table 20-6, pages 175 and 176
   //set mode to CTC, TOP value of OCR1A, WGM1[3:0] -> 0100
   TCCR1A &= ~((1 << WGM11) | (1 << WGM10)); // WGM11 and WGM10 unset
   TCCR1B |= (1 << WGM12);   // WGM12 set
   TCCR1B &= ~(1 << WGM13 ); // WGM13 unset

   //Register that will contain the value to be compared with
   OCR1A = 625; //625 counts according to prescaler of 64 for 5ms (200Hz) delay, 2.5ms / (1/(16Mhz/64)) = 625 counts

   //Enable Compare Output A mode
   TIMSK1 = (1 << OCIE1A);
   sei();
   for(;;){
   }
   return 0;
}

ISR(TIMER1_COMPA_vect){
   PORTB ^= (1 << PB1);
}

 

Last Edited: Sat. Jul 14, 2018 - 10:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR(TIMER1_COMPA_vect){
   PORTB ^= (1 << PB1);
}

 

remember  this flipping will provide 1/2 the irq freq.  An irq of 1000Hz will show as 500 pulses per sec (1000 edges going up & down)

 

desired 200Hz irq (edges) will show as 100Hz pulses.  This hidden factor of two often knocks programmers out of their car seats.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

ISR(TIMER1_COMPA_vect){
   PORTB ^= (1 << PB1);
}

 

remember  this flipping will provide 1/2 the irq freq.  An irq of 1000Hz will show as 500 pulses per sec (1000 edges going up & down)

 

desired 200Hz irq (edges) will show as 100Hz pulses.  This hidden factor of two often knocks programmers out of their car seats.

Thanks for warning. I noticed it and that's why OCR1A is set with 625 and not the value that results in 5ms delay which would be 1250. 625 is actually for 2.5ms delay. Tomorrow I'll proceed to next step.

Last Edited: Sat. Jul 14, 2018 - 11:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 I noticed it and that's why OCR1A is set with 625

Sorry chief, you got it backwards.   We want 200 irqs/sec (led toggle edges)...  If you toggle at 4 times a sec (4Hz), due to toggling you'd see the led flash at 2Hz.

So 200 toggles a sec will flash the led at 100Hz.   So if you scope it beware ONLY THEN so you don't say why don't I see 200Hz?

 

Anyhow, 200 something a second is 5ms  (0.005 sec) separation between them.

 

Note dividing by period is same as mult by freq, which is 16000000/64

 

So the count needed is [0.005*16000000/64] minus 1  or 1249  ...this will check the switch 200 times a sec--one SwitchAcount  and SwitchBcount every 5ms

 

 

 

 

 

     

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so if the idea is the 200 times a second, that will be in fact 100Hz and 1249 counts. I just need to change the counting value in OCR1A.

 

Now that this in between task is done, I'm going back to the code from post #19 and try again to make it work!

 

And to make it clear, please confirm or deny each of the following:

 

1 - Active-Low means that "something happens" when I short whatever it is to GND. In other words, the normal state is at about 5V, and when a button (or whatever is pressed), the voltage goes momentarily to 0V.

2 - Active-High means that "something happens" when I short whatever it is to +5VDC. In other words, the normal state is at about 0V, and when a button (or whatever is pressed), the voltage goes momentarily to 5V.

3 - The code in question (from post #19) is supposed to be for hardware in Active-Low or Active-High?

4 - The LED the will toggle in 3, is to be Active-Low or Active-High?

 

Thanks

Psy

Last Edited: Sun. Jul 15, 2018 - 08:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I did the following test with the code from post #19.

 

I commented the following line in main():

LED_OUTPUT ^= get_key_press(0x0c);

 

and added the following to check if timer was running:

if(TIFR0 & (1 << TOV0))
         PORTB ^= (1 << PB1);

 

I'm not sure this is the best approach but I get a frequency on scope of 61Hz. So, even if this is not the best was to check if timer is overflowing and triggering an interrupt, at least I know that TOV0 is being set. That tells me the timer is running, right?

 

And I have another question about the code, or  better, the comments in the code. Why in the line where the prescaler is set, there is a comment saying "divide 256 * 256". What is this supposed to mean?

 

Also in my case, I'm not sure if this frequency of 61Hz is exactly the frequency the count gives. I mean, if I use a prescaler of 256, I get 16Mhz/256 = 62.5Khz. This means a tick (or count) every 1/62500 of a second or 16us. As this is an 8 bit counter, the overflow occurs every 256 ticks, meaning after 16us * 256 = 4096 us. This means a frequency of 244.14Hz. On scope will show up a half of this value due to toggling. Curiously the frequency showing up on scope is half of hlaf of 244Hz, I mean 61Hz * 4 = 244Hz.

 

So where the 61Hz comes from? Or am I going wrong with the math?

Last Edited: Sun. Jul 15, 2018 - 09:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so if the idea is the 200 times a second, that will be in fact 100Hz and 1249 counts. I just need to change the counting value in OCR1A.

Now that this in between task is done, I'm going back to the code from post #19 and try again to make it work!

 

Does the 200Hz debounce work?  Once you have the IRQ running, it is only a few minutes to have it all ready.

Its like you are wandering in the AVR desert, going from town to town

 

So where the 61Hz comes from

if you are getting 16000000/256/256=244 irqs per second, why do you think you see a 122 square wave?  Are you sure you see 61Hz?

could be, since you are checking the irqflag in main, you only catch it half the time (since it is immediately handled)...that would make tha apparent freq less.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sun. Jul 15, 2018 - 03:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Ok, so if the idea is the 200 times a second, that will be in fact 100Hz and 1249 counts. I just need to change the counting value in OCR1A.

Now that this in between task is done, I'm going back to the code from post #19 and try again to make it work!

 

Does the 200Hz debounce work?  Once you have the IRQ running, it is only a few minutes to have it all ready.

Its like you are wandering in the AVR desert, going from town to town

 

So where the 61Hz comes from

if you are getting 16000000/256/256=244 irqs per second, why do you think you see a 122 square wave?  Are you sure you see 61Hz?

could be, since you are checking the irqflag in main, you only catch it half the time (since it is immediately handled)...that would make tha apparent freq less.

 

 

Indeed... I made the toggle inside the ISR vector and it shows correct frequency! 122Hz is because of the toggling thing.

About the original code from post #19, now I need to find a way of checking if it is working!

 

And the math I do is:

 

Crystal Freq / Prescaler factor

16Mhz / 256 = 62.5Khz

 

This means 1/62.5Khz seconds = 16us for each increment in TCNT0.

As Timer0 is 8-bit, the overflow takes 16us * 256 = 4096us to occur.

This means the flag will be set at a rate of 1/4096us = 244.14Hz.

I'm just not sure how it makes of this a 50% Duty Cycle and why  this is not more like a pulse and then the TVO0 flag would be set to 0 because the ISR routine is just a line of code and the remaining time was at 0V.

Something like this:

____|____|____|____

 

where each '|' is the TOV0 is set to 1 and immediately set to 0 because the ISR is just that line of code.

Instead, we have something like:

 

__|--|__|--|__|--|__

 

 

Anyway, I want to move on!

 

 

So, about the code of post #19, I'm going to try to use only a push-button at PD2 and a LED at PB1.

Push-Button is Active-Low. Meaning that the pin is using a 10k ohm pull-up resistor and the push-button has one lead to that uC pin and the other lead to GND. When I press the push-button, it sets 0V at PD2.

LED at PB1 has one lead (+ lead) connected to PB1 and the other lead (- lead) connected to a 470 ohm resistor that is connected to GND.

 

Is this the way the hardware should be set to work correctly with the code? 

Last Edited: Sun. Jul 15, 2018 - 05:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where is that link to a post where there was sort of a table with the current result of all the bitwise operations taking place inside the ISR of code from post #19? I can't find it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a feeling it was a link I gave to an analysis of danni's code by Johan Ekdahl

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I have a feeling it was a link I gave to an analysis of danni's code by Johan Ekdahl

Yes it was! I think the code is working and the return of the get_key_press() is just the address of the button pressed after debounced, right? In that case, if I want a LED to light ON I need to have a LED connected to the pin the push-button is connected to, no?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found the link:

 

Here for future reference.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Personally, I think you should stick with the simple counter method---why? it is simple to understand and debug & get working.  Getting the IRQ running is the hardest part & you already have that going (with a few fumbles along the way).

 

The other method is (Danni) great, but you will fall into an evil cave & need rescued over & over because it has more complex/convoluted details. Even though what you have should already be working, it is not--so you are about to wander into that cave seeking many solutions from the medicine man.

 

Soon you will be in the winners circle, lapping up the adulation,  big prize money, and maybe a free t-shirt.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, if I get my questions answered I bet with myself I'll get there! What I can't do is changing my mind constantly which I already did to try to accomplish your last suggestion (the 200Hz thing). I need to stick to this and I don't need to understand all and every detail of the code. I'll be happy to just understand the way it works so that I can adapt it to my code! That's all.

 

And I have a couple of questions about it! I was reading the walkthrough I just posted about and it's said that the variables all starts with 0. But any of the variables were assigned with a 0. So how do we know they don't have trash by the start of the program?

Another question is that one I made above about the return value of that function!

 

If I get these answer I might start doing the thing on my own I guess!

Last Edited: Mon. Jul 16, 2018 - 07:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was going to say that Danni's code is not rocket science though I guess it is a bit. But anyway all it ultimately does is monitor between 1 and 8 bits in a port. You pass in a mask to say which and how many you want to know about. In your case the mask value 0x0C means "two bits, bits 2 and 3 (counting 0 to 7)" it then returns 1 bits in bit position 2 or 3 or both or neither to indicate which of the two are pressed. So it will return 0x00 if neither are pressed, 0x04 if only bit 2 is pressed, 0x08 if only bit 3 is pressed or 0x0C if both 2 and 3 are pressed. It really is as simple as that (and hence not rocket science - even if it really is!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, in my case, I'll have to check when any of the buttons is pressed to take an action when it is, right?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just think of the return value of get_key_press() as if you were making a direct read on PINC or whichever input register you have selected. The only differences are two-fold: one is that rather than ANDing after the read to pick selected bits (as you might with a direct read of PINx) you can pass a mask INTO the function to mask bits beforehand. Also the output is "special" in that unlike a direct read of PINx where you might see bits "flickering" between 0 and 1 the function "smoothes" the output so you only see "solid" 0s and 1s.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I have already integrated the code in my project. I think it's working just fine!