Need help catching button presses

So I have this weird issue with my Hachi firmware, where it’s very responsive to button presses while running (clocked externally) but not so much when it’s not running.

As far as I can tell, the issue is in DigitalInputs::CheckIfChanged(). Specifically this line:

if ( dHwData[indexDigital].digitalHWState != dHwData[indexDigital].digitalHWStatePrev) { // and bounce time elapsed // REVIEW BOUNCE ROUTINE

If I quickly tap a button while Hachi is running, it catches it fine. If it’s not running, the if-check fails and there’s no response. If I hold the button a little longer, it gets picked up. There’s a comment there about checking the bounce time – where is that check done? and could something be changing the bounce time?

I see BOUNCE_MILLIS is set in DigitalInputs.h but never used. The encoder seems to have a lot of bounce time logic, but nothing in the digital inputs.

I just tried setting it so Hachi didn’t run when receiving midi clock, to see if something about getting clocks was affecting the response time, but that didn’t help. So it’s clear that something about my putting Hachi into the “running” state is causing the change.

But that’s weird because the logic to respond to buttons goes directly from DigitalInputs::DigitalAction, where I added a call to Hachi to handle the button event. I don’t see how it could affect the response in CheckIfChanged. :man_shrugging:

Hey Mike! @francoytx is currently on vacation in the wild patagonic forests but he will catch up with this issue as soon as he gets back to the office.

1 Like

Is @francoytx back? I’m still confused on this one.

Hello @mike!

I am back yes :slight_smile:
Did you fork or clone the GitLab repo?
Is your code available to take a peek into it?

I can’t tell how the “running” state is affecting the behavior of the controller :S

I can tell you that BOUNCE_MILLIS is not used in digitals (it was at some point, that’s why it’s there) because the logic is a bit different from the encoder switches.
Each digital element is scanned every DIGITAL_SCAN_INTERVAL = 36 ms with some logic to check all modules within those 36ms equally spaced.

The debounce is embedded in this interval check.

Did you use some prints to show this?
When it’s running it may be passing through here more often than when it’s not?

It’d be weird that if the “running” flag isn’t near this check, the check would fail.

Let me peek into the code and maybe I can see a bit more of the general picture.

Welcome back! I hope you had a good trip :slight_smile:

My fork is here: https://github.com/perkowitz/hachi-yaeltex/tree/hachi

Um… I forget exactly but I verified that the code that picks up the button presses wasn’t being executed. At the moment, the way it’s working is if I hold down the button for a second or so, the press is picked up.

This might be a clue: I think it affects the encoders too. If it’s not “running” then turning the encoders doesn’t register anything, but they work fine when I’m running.

Could it be that I am taking up cycles when not running and it’s not having much of a chance to scan for changes? I can’t think how my code could be affecting it otherwise. The problem might be in Hachi::Loop() – https://github.com/perkowitz/hachi-yaeltex/blob/hachi/ytx-controller/Hachi.ino#L191

thanks for any help you can give!

Thank you!

The fact that the problem affects both encoders and digitals (and I’d venture to say that if you had analogs, they’d also work weird when running) says that when Hachi is not running the loop doesn’t have the same cycle time.
You can test this opening the serial port and sending ‘t’ to enable the test mode, and them ‘m’ to print the loop time in micros.

You can set Hachi to run and stop and see if the loop time is modified.

In particular, I see Line 92 on Hardware.ino does a feebdack update.

I also that hardware.Update() is called when hachi is not running.

The idea of feedbackHw.Update(); is to run once every main loop and dispatch all the LEDs that have been updated in the buffer.

Not to be called everytime there is an update.
I don’t know if the difference is clear.

The update process starts communications with the feedback microcontroller that is pretty tight regarding back and forth status signals and flags.

Maybe calling this update method so much is leaving it in a weird state that is not allowing the rest of the code to run smoothly.

I’d leave the loop to be the only place where feedbackHw.Update(); is called and see what happens.
In the rest of the code, only fill the feedbackUpdateBuffer and then the Update method will do the rest every loop

Okay, so I tried some things.

I disabled the call to feedbackHw.Update() since it’s not needed, but that didn’t fix the issue.

I did check the loop times, and the non-running loop time is sometimes very high because of the Draw() call in line 233. Without that in, the button response is fine. (Though, the loop times are usually around 160 micros, but every 10th loop is about 860 micros :man_shrugging:)

So the draw() call was the problem, but part of the reason it’s there was because I have not been able to get things to draw properly when I put them in the Init() function. The code runs but the buttons don’t get lit up. But since my code thinks it was done, it doesn’t redraw things until they change. Any idea why I can’t light up the buttons at the beginning, and is there a way for me to tell when I can do it?

Anyway, right now it’s working so that it redraws everything if I hit a certain button, and no redraw in Loop(). That works great, but I have to hit the button on startup to get everything drawn properly. Thanks for the help!

This is because the digitals are read every certain amount of loops depending on how many digital elements you have on your controller.

Every element is read every 36 ms and inside 36 ms all the elements are read, if you have 16 elements, the elements will be read every ~2.5ms (160 us x 10 + 860 us = 2460 micros)

0ms = read element 0
2.5ms = read element 1
5 ms = read element 2
... and so on
36 ms = read element 0 again

That’s why some loops are longer.

Great that you found what was halting the microcontroller!

Yes, it’s better that when you press a button, you fill the feedbackUpdateBuffer and then just every time the loop runs and there is something to update, it will be pushed to the feedback uC

The Draw at the init() should work :confused:

In setup.ino I see that hachi.init() is commented

Anyway, glad you could advance a little with the help :slight_smile:

ah, makes sense.

The hachi.init() call was commented because it wasn’t working, and instead I call it from the loop if it hasn’t been called before. I just tried uncommenting it but buttons are still not getting drawn. It’d be nice to figure it out so I can get things drawn right (and also so I can eventually create my own animation instead of the rainbow)