Does GPIO Linux framework support to change mode between GPIO and IRQ - linux-device-driver

I checked the sysfs of GPIO, it only supports to configure the direction (in, out), active_level, edge.
I don't see it supports to change mode between GPIO and interrupt. Do any you know it ? Or any suggest.
Example:
Some GPIOs can supports either GPIO or IRQ. So I would like to change mode it under Linux via sysfs.
Thanks in advance.

The GPIO controller (and thus driver) will provide that support if any. In that case GPIO controller is registered as an interrupt controller. There are a lot of examples, like gpio-intel-mid.c where you have:
retval = gpiochip_irqchip_add(&priv->chip,
&intel_mid_irqchip,
irq_base,
handle_simple_irq,
IRQ_TYPE_NONE);
if (retval) {
dev_err(&pdev->dev,
"could not connect irqchip to gpiochip\n");
return retval;
}

Related

SPI set up on stm32

i use to set up Display with SPI communication, and i use GPIO Pins CLK, MOSI, RES, DC, CS,
my question is how to set up GPIO_Output pins RES, DC, CS
GPIO Set up
i need to leave default or need to set up pool up?
thank you
For push-pull type output, you don't need the internal pull-up/pull-down.
If you use open-drain output and your board does not have the necessary resistors, you can use the internal pull-up or pull-down, depending on what is required.

STM32 F3 I2C on Port F SCL Push-Pull Failure

We're currently using STM32F373CC micros in several of our designs. Part of our standard design has an EEPROM connected via I2C. We have our own hardware layer that is tried and proven over the decades. However, it relies on the I2C port pins having pull-ups connected externally.
On some of our new designs we have designed out the pull-up on the SCL line and have set the port pin to Push-Pull mode. In theory, this should be no problem. However, what we've found is that the micro seems to be treating the port pin as open-drain regardless of the setting. For this particular design, we're using PF6 and PF7 as SCL and SDA respectively. With no pull-up connected, the SCL line is flat-lined. With internal pull-up enabled, the SCL line is pulsing, but the rise time is so long it's not working.
Nothing in the reference manual or the datasheet says anything about this issue. In the errata sheet we have (V4), there's quite a bit about the GPIO and I2C, but nothing that seems to relate to this.
For what it's worth, I'll copy and paste the relevant bit of the initialisation:
switch( kasPinMap[eSCL].lwI2CNum )
{
case 1: RCC_APB1ENR.I2C1EN = TRUE; nI2CEEpsRegisters = (void*)&I2C1_CR1; break;
case 2: RCC_APB1ENR.I2C2EN = TRUE; nI2CEEpsRegisters = (void*)&I2C2_CR1; break;
}
//configure the pins
DIO_vConfigure( kasPinMap[eSCL].ePort, kasPinMap[eSCL].lwBit, DIOkeM_Alternate, DIOkeD_PushPull, DIOkePU_None, DIOkeSP_Medium, kasPinMap[eSCL].lwAFN );
DIO_vConfigure( kasPinMap[eSDA].ePort, kasPinMap[eSDA].lwBit, DIOkeM_Alternate, DIOkeD_OpenDrain, DIOkePU_None, DIOkeSP_Medium, kasPinMap[eSDA].lwAFN );
//reset and enable the peripheral
nI2CEE_vReset();
In the debugger, GPIOF looks like this:
AFR values are set to 4.
The I2C registers look like this:
And the RCC registers look like this:
Our Technical Director mentioned that to comply with the I2C standard and allow for multi-master mode, both SCL and SDA should both be open-drain. However, all we have here is the F3 and the EEPROM.
Any thoughts on why we might not be getting the push-pull action out of the SCL line would be appreciated.

How to implement a Low-Level LL_GPIO_ReadPin( function in STM32f103

Using CubeMX and CubeMxIDE an example for reading a button if using HAL drivers works.
https://karedox.com/?p=193 .
However, I need to read a GPIO pin using low-level drivers.
But apparently, LL_GPIO_ReadPin(SW_GPIO_Port, SW_Pin)
is not implemented
whereas
LL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin) does not give an error.
Is there a low-level driver solution for GPIO_ReadPin?
why just not:
!!(SW_GPIO_Port -> IDR & (1 << SW_PIN))

Simpe C code physically breaks nucleo boards

Code below physically breaks nucleo boards. 2 so far.
ST links is unable to connect and boards are not detected.
first dead one was xncleo stm32f411re, another one is nucleo stm32f446re.
I'm a complete beginner and that is pretty much my first code.
and 2 boards dead;) The question is why it may happen? or can one reset the board harder that normal jumper reset
int main()
{
RCC->AHB1ENR = (1<<0);
GPIOA->MODER = (1<<5);
while(1)
{
GPIOA->ODR |= (0<<5);
}
}
This is similar to this question ->
https://electronics.stackexchange.com/questions/204996/stm32-st-link-cannot-connect-to-mcu-after-successful-programming
, answer to which helped me to restore the board, however answers to my problem in this thread are also very helpfull.
some pins used for debugging need to have some settings. if you change those settings the debugger cannot connect anymore. you need to set the debugger to connect under reset when the debug pins are in the initial corrct state. stm32 processors cannot be bricked this simple way.
so not listen to the advices that you need to use crappy STM libraries. just only set the pins you use, not the whole port.
Yes, your problem is with the line "RCC->AHB1ENR = (1<<0);". That enables power to GPIOA, but disables power to the other GPIOs (B,C,D,E, and H on the F411), which includes the SWD pins.
Edit:Reseting problem solved here: https://electronics.stackexchange.com/questions/204996/stm32-st-link-cannot-connect-to-mcu-after-successful-programming
the reason problem occured solved below
Ok, it doesn't physically break the board. Needed hard reset - shorting rst and sb11 pins on nucleo stm32f446re. didn't try on xnucleo yet.
User P__J__ got it right in the comment. I'll cite:
just do not assign to the moder. use |= or &= instead – P__J__
Done.
And the fixed code:
int main()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER |= GPIO_MODER_MODE5_0;
while(1)
{
GPIOA->ODR |= GPIO_ODR_OD5;
}
}

GPIO IRQ on ARM based Embedded Linux

I'm trying to program an GPIO IRQ on AT91SAM9M10-EKES evaluation board.
I successfully registered the IRQ, and the IRQ is working.
However, some interrupts are missed. I'm sending 26, and I get only 22.
The code:
static irqreturn_t wiegand_interrupt(int irq, void *dev_id){
atomic_inc(&counter);
printk(KERN_WARNING "IRQ recieved, counting... %d\n",atomic_read(&counter));
return 0;
}
irq1 = gpio_to_irq(AT91_PIN_PA21);
if (irq1 < 0) {
err = irq1;
printk("Unable to get irq number for GPIO %d, error %d\n",AT91_PIN_PA21, err);
goto fail;
}
err = request_irq(irq1,wiegand_interrupt,0 ,"wiegand",NULL);
irq2 = gpio_to_irq(AT91_PIN_PA20);
if (irq2 < 0) {
err = irq2;
printk("Unable to get irq number for GPIO %d, error %d\n",AT91_PIN_PA21, err);
goto fail;
}
err = request_irq(irq2,wiegand_interrupt,0 ,"wiegand",NULL);
This is not the whole driver, but this is the actual part that deals with the IRQ.
If someone see a problem in the code, or can suggest a way to know why I lose 4 interrupts, please reply. I'm stuck on this for hours... :(
Thanks.
Ramon.
I assume you are triggering your interrupts with an external system (maybe a microcontroller or something that can toggle the GPIOS). Since I do not see a real ack of the interrupt, I assume the external system does not wait for the interrupt to be handled to maybe trigger a new one.
printk is a very slow function and that's why you can miss some interrupts: a new one can be triggered while you are still handling the previous one.
So I would advise not to use printk in the handler. If you want to achieve something like this, it would be better to use a tasklet or a workqueue as the bottom half of the interrupt handler.
I can only recommend the reading of the Chapter 10 of Linux Device Drivers.
Oh and by the way, your IRQ handler should not return 0 but IRQ_HANDLED.
Ok, actually, the problem is that I used the GPIO pins, while the GPIO pins don't support IRQF_TRIGGER_FALLING flag, which is exactly what I need. so probably, the interrupt handler doesn't recognize the signal correctly.
I found out that I need to use the external pins for IRQF_TRIGGER_FALLING enables IRQ's.