How to do GPIOPin button Interrupt correctly
dirkarnez opened this issue · comments
I have gone through some examples and documentation and came up with this:
#include "kernel.h"
#include <circle/timer.h>
#include <assert.h>
#define GPIO_BUTTON 17 // connect a button between this GPIO and GND
static const char FromKernel[] = "kernel";
CKernel::CKernel (void)
: m_Screen (m_Options.GetWidth (), m_Options.GetHeight ()),
m_Timer (&m_Interrupt),
m_Logger (m_Options.GetLogLevel (), &m_Timer),
m_GPIOManager (&m_Interrupt),
m_ButtonPin (GPIO_BUTTON, GPIOModeInputPullUp, &m_GPIOManager)
{
m_ActLED.Blink (5); // show we are alive
}
CKernel::~CKernel (void)
{
}
boolean CKernel::Initialize (void)
{
boolean bOK = TRUE;
if (bOK)
{
bOK = m_Screen.Initialize ();
}
if (bOK)
{
bOK = m_Serial.Initialize (115200);
}
if (bOK)
{
CDevice *pTarget = m_DeviceNameService.GetDevice (m_Options.GetLogDevice (), FALSE);
if (pTarget == 0)
{
pTarget = &m_Screen;
}
bOK = m_Logger.Initialize (pTarget);
}
if (bOK)
{
bOK = m_Interrupt.Initialize ();
}
if (bOK)
{
bOK = m_Timer.Initialize ();
}
if (bOK)
{
bOK = m_GPIOManager.Initialize ();
}
return bOK;
}
TShutdownMode CKernel::Run (void)
{
//m_Logger.Write (FromKernel, LogNotice, "Compile time: " __DATE__ " " __TIME__);
m_ButtonPin.ConnectInterrupt (InterruptHandler, this);
m_ButtonPin.EnableInterrupt (GPIOInterruptOnRisingEdge);
while (1)
{
u32 nNumber = m_Random.GetNumber () % 100; //0 到 4,294,967,295
// static const char ScreenMsg[] = "Hello screen!\n";
//m_Serial.Write (ScreenMsg, sizeof ScreenMsg-1);
static const char SerialMsg[] = "in the loop!\n";
m_Serial.Write (SerialMsg, sizeof SerialMsg-1);
CString Source;
Source.Format ("%u", nNumber);
m_Serial.Write (Source, Source.GetLength());
CTimer::SimpleMsDelay (1000);
// char Buffer[100];
// int nBytesRead = m_Serial.Read (Buffer, sizeof Buffer);
// if (nBytesRead > 0)
// {
// m_Screen.Write (Buffer, nBytesRead);
// }
}
m_ButtonPin.DisableInterrupt ();
return ShutdownHalt;
}
void CKernel::InterruptHandler (void)
{
static const char SerialMsg[] = "Hello UART!\n";
m_Serial.Write (SerialMsg, sizeof SerialMsg-1);
}
void CKernel::InterruptHandler (void *pParam)
{
CKernel *pThis = (CKernel *) pParam;
pThis->InterruptHandler();
}
But the button (i connect just a push button between GPIO 17 aka pin 11 and GND) is not working, not sure whether my circuit is wrong or my code is wrong. Expected "Hello UART!" printed in serial for button press. the while true loop is perfectly working. Thanks!
That should be OK. I did a quick test on a RPi 5 with your code, and it works! Perhaps your wiring is not OK? Also the GPIO interrupt is triggered immediately, because you are using GPIOInterruptOnRisingEdge
. Perhaps GPIOInterruptOnFallingEdge
would be better. But this shouldn't be the problem here. Which RPi model are you using?
Thanks @rsta2 , i am using raspberry pi 4b, the circuit is this. no preference on GPIOInterruptOnRisingEdge
or GPIOInterruptOnFallingEdge
, but it seems mine does not work (even i short circuit the GPIO 17 and GND to mimic pressed buttion.
Or should i give 3v3 to GPIO 17?
Thx, i tried three other pins still not working, i am using headless mode, does it affect the GPIO? Did you have special settings in for example cmdline.txt, config.txt ?
logger: Circle 46 started on Raspberry Pi 4 Model B 4GB (AArch64)
logger: Revision code is c03111, compiler has been GCC 13.2.1
Is it possible that my compiler (on Windows) may do something differently? this is the zip of my sd card contents sdcard.zip, does it work for you too (GPIO18)? Thanks!
You have the same revision of the RPi 4B like me, but 4GB RAM. I have only 2GB, but this shouldn't make a difference. I tried your SD card contents, and I got the same behavior like you. The GPIO interrupt does not work. But interrupts generally work, because the timer can calculate the SpeedFactor.
The recommended toolchain for Circle builds can be downloaded here. You should still use the GNU C 12.2.Rel1 based toolchain (see more at the bottom of the page). I think this is the right download for you.
With the Linux version of this toolchain I build the attached kernel8-rpi4.img. Can you please extract it from the .zip archive and put it on the same SD card for a test? It does work here (with GPIO18).
Thanks for the patience, i have tried your binary and also my build using your recommended toolchain. Both does not work, i wonder if it is firmware mismatch (using tag "Step46") or my configure being wrong (./configure --raspberrypi 4 --realtime --prefix aarch64-none-elf- --multicore --c++17
)🤣🤣
thx, i see, after removed --realtime
and rebuilt everything, it does not work. I am not a ARM guy but would like to curiously ask: Is it possible for RPi 4B in different RAM to have different internal structure like GPIO address mapping?
i deleted the circle repo, redo git clone circle, reconfigure and recompile everything
that should be sufficient
Could you please recommend some software / hardware tricks to check if the pins or the Pi itself is really broken so i can save money to buy another one 🤣🤣. Apparently it looks good since the RX / TX pins are working for serial print, and i am desperate for using circle in my final year project 🤣🤣
Wow thanks, going to flash the OS and try!
@rsta2 my bad bro. It is my power supply not having enough current to drive all GPIOs. Official power supply rated 3A, i was using power from computer usb port😬😬.
However, i see the interrupt working, but in unexpected way: it seems the interrupt and the SimpleMsDelay
in while true loop are having racing condition?
When i pressed the button for interrupt, the "Hello UART!\n";
may not be printed, "in the loop!\n";
keeps printing per period of time. But "Hello UART!\n";
may appear multiple times later like they are from the queue.
To keep the button working more responsively, i have to press the button in high speed. Doesn't interrupt mechanism debounce the button signal?
@rsta2 i see and thx so much bro! Let me close this