rsta2 / circle

A C++ bare metal environment for Raspberry Pi with USB (32 and 64 bit)

Home Page:https://circle-rpi.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.
image

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 ?

image
It is:

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).

kernel8-rpi4.zip

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

image
image
Finally it works perfectly! I use my own debounced button connected to 3.3V with rising edge and pulled down interrupt GPIO 18