I am developing a kernel module for an embedded device, The device core is Toradex iMX6DL.
So I have an IO-Expander of mcp23xxx series on this device and I can work with its GPIOs. I can set them as input/output and get/set their values.
I need to use one of them as an interrupt, this is the part of my code for setting interrupt:
static irqreturn_t r_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
{
printk(KERN_DEBUG "interrupt received (irq: %d)\n", irq);
//do some stuff here
return IRQ_HANDLED;
}
...
if(gpio_request(497, 0)==0)
{
int result;
gpio_direction_input(497);
gpio_set_debounce(497, 100);
gpio_export(497,false);
irqNumber =gpio_to_irq(497); // map your GPIO to an IRQ
printk("irq number : %d\r\n",irqNumber);
result = request_irq(irqNumber, // requested interrupt
(irq_handler_t) r_irq_handler, // pointer to handler function
IRQF_TRIGGER_RISING, // interrupt mode flag
"irqHandler", // used in /proc/interrupts
NULL); // the *dev_id shared interrupt lines, NULL is okay
printk("irq request for pin %d result:%d \r\n",497,result);
if(result == SUCCESS)
printk("irq request for pin %d succeeds\r\n",497);
}
The result of gpio_to_irq() is '-6' and the result of request_irq() is '-22', What should I do to get this GPIO's interrupt?
Related
I have a smart card IC module, and I want to create a Linux device driver for it. This module is using SPI as the controlling line and has an interrupt line to indicate whether a card is ready. I know how to create a SPI device in Linux kernel and how to read data in the kernel when the interruption happens. But I have no idea on how to transfer the data to the user space (maybe need to create a device node for it), and how to give the user space a interruption to notify it. Does anyone have some suggestion?
One way you can go about this is by creating a devfs entry and then having the interested process open that device and receive asynchronous notification from the device driver using fasync.
Once you have the notification in user space you can notify other interested processes by any means you deem fit.
I am writing a small trimmed down example illustrating this feature.
On the driver side
/* Appropriate headers */
static int myfasync(int fd, struct file *fp, int on);
static struct fasync_struct *fasyncQueue;
static struct file_operations fops =
{
.open = charDriverOpen,
.release = charDriverClose,
.read = charDriverRead,
.write = charDriverWrite,
.unlocked_ioctl = charDriverCtrl,
// This will be called when the FASYNC flag is set
.fasync = myfasync,
};
static int __init charDriverEntry()
{
// Appropriate init for the driver
// Nothing specific needs to be done here with respect to
// fasync feature.
}
static int myfasync(int fd, struct file *fp, int on)
{
// Register the process pointed to by fp to the list
// of processes to be notified when any event occurs
return fasync_helper(fd, fp, 1, &fasyncQueue);
}
// Now to the part where we want to notify the processes listed
// in fasyncQueue when something happens. Here in this example I had
// implemented the timer. Not getting in to the details of timer func
// here
static void send_signal_timerfn(unsigned long data)
{
...
printk(KERN_INFO "timer expired \n");
kill_fasync(&fasyncQueue, SIGIO, POLL_OUT);
...
}
On the user land process side
void my_notifier(int signo, siginfo_t *sigInfo, void *data)
{
printf("Signal received from the driver expected %d got %d \n",SIGIO,signo);
}
int main()
{
struct sigaction signalInfo;
int flagInfo;
signalInfo.sa_sigaction = my_notifier;
signalInfo.sa_flags = SA_SIGINFO;
sigemptyset(&signalInfo.sa_mask);
sigaction(SIGIO, &signalInfo, NULL);
int fp,i;
fp = open("/dev/myCharDevice",O_RDWR);
if (fp<0)
printf("Failed to open\n");
/*New we will own the device so that we can get the signal from the device*/
// Own the process
fcntl(fp, F_SETOWN, getpid());
flagInfo = fcntl(fp, F_GETFL);
// Set the FASYNC flag this triggers the fasync fops
fcntl(fp, F_SETFL, flagInfo|FASYNC);
...
}
Hope this clears things up.
For more detailed reading I suggest you read this
I want to print messages from my STM32 Nucleo-L073RZ microcontroller. How should I go about it?
Should I use UART? Where can I get the corresponding code?
#include "stm32l0xx.h"
#include "stm32l0xx_nucleo.h"
#include "stm32l0xx_hal.h"
#include "stdio.h"
static void GPIO_Init (void);
static void UART_Init (void);
int main(void)
{
HAL_Init();
GPIO_Init();
printf("Hello");
while(1)
{
}
}
static void GPIO_Init(void)
{
BSP_LED_Init(LED2);
BSP_LED_On(LED2);
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA13*/
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}
/*Uart Init Function*/
static void UART_Init(void)
{
}
void EXTI4_15_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN)
{
BSP_LED_Toggle(LED2);
counter();
}
int counter()
{
int i;
i = 0;
i++;
printf("/n %d", i);
}
How do I display the counter on my PC? I want the number of times the interrupt is given to be seen on PuTTY. Should I interface an UART or is it possible to print?
You can use UART on the Nucleo
All Nucleo boards have a built-in UART-to-USB module that automatically transmits data to a Serial Port on your computer. If on windows, open your Control Panel, go to Device Manager, and under COM Ports you should see your Nucleo.
Initialize the UART Peripheral
Reference your Nucleo user manual to see which UART pins connect to the USB port (STM32CubeMX might have these already mapped).
When initializing the peripheral, select a baud rate like 9600, and remember it
Configure PuTTy
Enter the COM port of the Nucleo and the Baud Rate that you selected earlier, and select Serial as the transmission method. You might have to disable some of the hardware flow control options if they are enabled
Code to transmit
HAL has functions for transmitting over UART. Something like HAL_UART_Transmit(...). You'll have to look up how to use the function specifically, plenty of great tutorials out there.
I personally use sprintf to print nicely formatted strings over UART like this:
char buf[64];
sprintf(buf, "Value of counter: %d\r\n", i);
// change huartX to your initialized HAL UART peripheral
HAL_UART_Transmit(&huartX, buf, strlen(buf), HAL_MAX_DELAY);
First Add use UART Handler and its init in this function i used UART2 change it to your periph if you use Stm32 Cube or IDE just select the periph it is automatically generated.
Use this function in order to use the print function it's act the same like Printf.
#include <stdint.h>
#include <stdarg.h>
void printmsg(char *format,...) {
char str[80];
/*Extract the the argument list using VA apis */
va_list args;
va_start(args, format);
vsprintf(str, format,args);
HAL_UART_Transmit(&huart2,(uint8_t *)str, strlen(str),HAL_MAX_DELAY);
va_end(args);
}
In your Counter function just Change printf to printmsg
int counter()
{
int i;
i = 0;
i++;
printmsg("/n %d", i);
}
Remember to change Printmsg uart Handler .
This is my first stack overflow post (long time lurker), so sorry in advance if this question isn't well worded.
I'm trying to make a kernel module to emulate keypresses when a user presses a button, and using http://www.staerk.de/thorsten/My_Tutorials/Writing_Linux_kernel_modules as an example.
It does simulate a keypress when the module is initialized, but when I send an interrupt and try to run the same code the entire virtual machine freezes.
Here's snippits of my code:
static void got_char(struct work_struct *taskp)
{
struct myprivate *myp = container_of(taskp, struct myprivate, task);
if ((myp->scancode == 0x01) || (myp->scancode == 0x81))
{
printk ("You pressed Esc !\n");
println ("Pressed ESC ! \n");
ch=65;
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
}
else if (myp->scancode == 0x1D) {
printk ("You pressed Ctrl!\n");
}
else {
printk("Scancode = %d", myp->scancode);
}
}
irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
static int initialised = 0;
/*
* Read keyboard status
*/
myp->scancode = inb(0x60);
if (initialised == 0) {
INIT_WORK(&myp->task, got_char);
initialised = 1;
}
else {
PREPARE_WORK(&myp->task, got_char);
}
schedule_work(&myp->task);
return (irq_handler_t) IRQ_HANDLED;
}
/* Helper method to print stuff to the terminal */
static void println(char *string)
{
tty = current->signal->tty;
(tty->driver->ops)->write (tty, string, strlen(string));
((tty->driver->ops)->write) (tty, "\015\012", 2);
}
/* Initialize the module and Register the IRQ handler */
static int __init keybrd_int_register(void)
{
myp = kmalloc(sizeof (*myp), GFP_KERNEL);
int result;
/* Request IRQ 1, the keyboard IRQ */
result = request_irq (1, (irq_handler_t) irq_handler, IRQF_SHARED, "keyboard_stats_irq", (void *)(irq_handler));
/* Test simulating keypress */
println ("inserting A ! \n");
ch=65;
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
if (result)
printk(KERN_INFO "can't get shared interrupt for keyboard\n");
return result;
}
Everything works as expected, except for when ESC is pressed, then my entire system just freezes and I have to restart my VM.
I've looked through many posts and forums online and can't find an answer.
Any suggestions would be appreciated, thanks in advance.
I am using i.mx6quad with debian jessie (3.14.60-fslc-imx6-sr).
I want co connect ov5642 camera module with PARALLEL 8BIT interface (using 8gpios for data and 3 for control signals).
I wrote a linux kernel module to service interrupts from control signals. Interrupts from VSYNC and HREF signals are serviced properly but when I connect a PCLK (about 8MHz) signal which is much faster than HREF or VSYNC my linux hangs up untill I disconnect a wire with PCLK (everything stucks).
To connect PCLK I use GPIO90 (DISP1_DATA22) but I tried also with other gpios.
Now My question is which GPIO should I use to service such fast signals like PCLK properly or what can i do to avoid linux hang ups ??
I include a linux kernel module code that I use.
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/gpio.h>
#include<linux/interrupt.h>
static unsigned int VSYNC_gpio_number=79;
static unsigned int HREF_gpio_number=76;
static unsigned int PCLK_gpio_number=90;
static unsigned int VSYNC_irqNumber;
static unsigned int HREF_irqNumber;
static unsigned int PCLK_irqNumber;
static irq_handler_t VSYNC_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs);
static irq_handler_t HREF_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs);
static irq_handler_t PCLK_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs);
int __init camera_module_test_init(void){//init_module()
int result=0;
printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
//VSYNC init
if(!gpio_is_valid(VSYNC_gpio_number)){
printk(KERN_INFO "GPIO TEST: invalid VSYNC GPIO\n");
return -ENODEV;
}
//HREF init
if(!gpio_is_valid(HREF_gpio_number)){
printk(KERN_INFO "GPIO TEST: INVALID HREF GPIO\n");
return -ENODEV;
}
//PCLK init
if(!gpio_is_valid(PCLK_gpio_number)){
printk(KERN_INFO "GPIO TEST: INVALID PCLK GPIO\n");
return -ENODEV;
}
//ledOn=true;
//VSYNC
gpio_request(VSYNC_gpio_number,"sysfs");
gpio_direction_input(VSYNC_gpio_number);
gpio_export(VSYNC_gpio_number,false); // causes gpioX to appear in sysfs /sys/class/gpio/
//HREF
gpio_request(HREF_gpio_number,"sysfs");
gpio_direction_input(HREF_gpio_number);
gpio_export(HREF_gpio_number,false);
//PCLK
gpio_request(PCLK_gpio_number,"sysfs");
gpio_direction_input(PCLK_gpio_number);
gpio_export(PCLK_gpio_number,false);
// GPIO numbers and IRQ numbers are not the same
//MAPPING GPIO NUMBERS TO IRQ NUMBERS
//---------
VSYNC_irqNumber = gpio_to_irq(VSYNC_gpio_number);
printk(KERN_INFO "GPIO_TEST: VSYNC signal is mapped to IRQ: %d\n",VSYNC_irqNumber);
//
HREF_irqNumber=gpio_to_irq(HREF_gpio_number);
printk(KERN_INFO "GPIO TEST: HREF signal is mapped to IRQ: %d\n",HREF_irqNumber);
//
PCLK_irqNumber=gpio_to_irq(PCLK_gpio_number);
printk(KERN_INFO "GPIO TEST: PCLK signal is mapped to IRQ: %d\n",PCLK_irqNumber);
//requests an interrupt line
//VSYNC
result=request_irq(VSYNC_irqNumber,(irq_handler_t)VSYNC_gpio_irq_handler,IRQF_TRIGGER_RISING,"VSYNC_gpio_handler",NULL);
if(result==0){ //if success
printk(KERN_INFO "GPIO_TEST: The VSYNC interrupt request result is: %d\n",result);
}
else{
printk(KERN_INFO "GPIO_TEST: The VSYNC interrupt request FAIL !!! (%d)\n",result);
return result;
}
//HREF
result=request_irq(HREF_irqNumber,(irq_handler_t)HREF_gpio_irq_handler,IRQF_TRIGGER_RISING,"HREF_gpio_handler",NULL);
if(result==0){ //if success
printk(KERN_INFO "GPIO_TEST: The HREF interrupt request result is: %d\n",result);
}
else{
printk(KERN_INFO "GPIO_TEST: The HREF interrupt request FAIL !!! (%d)\n",result);
return result;
}
//PCLK
result=request_irq(PCLK_irqNumber,(irq_handler_t)PCLK_gpio_irq_handler,IRQF_TRIGGER_RISING,"PCLK_gpio_handler",NULL);
if(result==0){// if success
printk(KERN_INFO "GPIO_TEST: The PCLK interrupt request result is: %d\n",result);
}
else{
printk(KERN_INFO "GPIO_TEST: The PCLK interrupt request FAIL !!! (%d)\n",result);
return result;
}
printk(KERN_INFO "MODULE LOADED.... WAITING FOR INTERRUPTION\n");
return result;
}
static void __exit camera_module_test_exit(void){ //cleanup_module(void){
printk(KERN_INFO "EXITING CAMERA_LKM_MODULE_TEST\n");
//unexporting GPIOs
gpio_unexport(VSYNC_gpio_number);
gpio_unexport(HREF_gpio_number);
gpio_unexport(PCLK_gpio_number);
//freeing IRQs
free_irq(VSYNC_irqNumber,NULL);
free_irq(HREF_irqNumber,NULL);
free_irq(PCLK_irqNumber,NULL);
//freeing memory
gpio_free(VSYNC_gpio_number);
gpio_free(HREF_gpio_number);
gpio_free(PCLK_gpio_number);
printk(KERN_INFO "GOODBYE world - MODULE CLOSED\n");
}
static irq_handler_t VSYNC_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs){
printk(KERN_INFO "* VSYNC Interrupt on rising! *\n");
return (irq_handler_t)IRQ_HANDLED;
}
static irq_handler_t HREF_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs){
printk(KERN_INFO "-- HREF interrupt! on rising --\n");
return (irq_handler_t)IRQ_HANDLED;
}
static irq_handler_t PCLK_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs){
printk(KERN_INFO "// PCLK interrupt! on rising //\n");
return (irq_handler_t)IRQ_HANDLED;
}
module_init(camera_module_test_init);
module_exit(camera_module_test_exit);
MODULE_LICENSE("GPL");
I can add that I am using hummingboard gate with available gpios shown in attached image.
hummingboard gate available gpios
It might be a silly question, but I haven't got it so far about DMA.
When doing memory to memory DMAing, it requires to allocate DMA buffer
(for example with dma_alloc_coherent()), then for each transfer we need to copy the buffer to the allocated memory (source buffer) and then trigger DMA transaction.
So, if it requires additional memcpy() for each transaction, what's the
benefit of using DMA?
Steps for copying source to destination - without DMA:
copy buffer (memcpy()) from source to destination
Steps for copying source to destination - with DMA:
copy buffer (memcpy()) from source to DMA buffer
trigger DMA transaction (which shall copy the buffer eventually to
destination buffer)
An example of this problem is with Ethernet driver, which need to copy from the recieved sk_buf into physical address of FPGA. In this case it shall requires copying the sk_buf into the DMA source buffer (from dma_alloc_coherent()) first.
If you can use dma_map_single() with the sk_buf pointer, then you do not have to copy it into a buffer allocated with dma_alloc_coherent(). There are many examples of this in network device drivers.
int dma_len = skb->len;
dma_addr_t dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
// error checking code here
// then send the dma_addr to the drvice
// when it is done, unmap it
dma_unmap_single(dev, dma_addr, dma_len, DMA_TO_DEVICE);
See the DMA Mapping API documentation for more details.
I guess my answer is no longer relevant to the post owner, but maybe it would help some other programmers in the future.
As mentioned in one of the comments here, if your FPGA have a DMA controller (which allows the FPGA to read the memory that has been mapped to the DMA), then you should be able to do DMA without memcpy() operations.
I will try to give here a short (as possible...) example of how it can be implemented in an Ethernet driver in the Rx flow (but there are more than one method of how to implement it and this is only a general example to understand the basic steps and concept). Please note that I've tried to simplify it, so do not try to compile it (this is not the full code - for a full Ethernet driver review, you can try start looking on this driver).
Now, let's focus on these basic steps:
Initialize the Rx Buffers
Rx Frame Reception
Prepare the Rx buffers for the next DMA transactions
Free the Rx Buffers
Initialize the Rx Buffers
static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags)
{
struct my_private *tp = (struct my_private *)dev->priv;
int ret = -ENOMEM;
int i;
tp->dma_buf_sz = BUF_SIZE_16KiB;
for (i = 0; i < DMA_RX_SIZE; i++) {
ret = init_rx_buffers(dev, i, flags);
if (ret)
goto err_init_rx_buffers;
}
return 0;
err_init_rx_buffers:
for (i = 0; i < DMA_RX_SIZE; i++) {
ret = free_rx_buffer(dev, i);
if (ret)
goto err_init_rx_buffers;
}
return ret;
}
static int init_rx_buffers(struct net_device *dev, int i, gfp_t flags)
{
struct my_private *tp = (struct my_private *)dev->priv;
struct sk_buff *skb = __netdev_alloc_skb_ip_align(dev, tp->dma_buf_sz, flags);
if (!skb) {
printk("Rx init fails; skb is NULL\n");
return -ENOMEM;
}
tp->rx_skbuff[i] = skb;
tp->rx_skbuff_dma[i] = dma_map_single(tp->device, skb->data,
tp->dma_buf_sz, DMA_FROM_DEVICE);
if (dma_mapping_error(tp->device, tp->rx_skbuff_dma[i])) {
printk("DMA mapping error\n");
dev_kfree_skb_any(skb);
return -EINVAL;
}
return 0;
}
Rx Frame Reception
/* should be called by the interrupt handler or NAPI poll method*/
static void receive_packets(struct net_device *dev)
{
struct my_private *tp = (struct my_private *)dev->priv;
unsigned int count = 0;
int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
unsigned int next_entry = tp->cur_rx;
while (count < rx_work_limit) {
int entry = next_entry;
/* read the status of the incoming frame */
int status = get_rx_status(tp);
/* check if managed by the DMA otherwise go ahead */
if (unlikely(status & dma_own))
break;
count++;
tp->cur_rx = get_rx_entry(tp->cur_rx, DMA_RX_SIZE);
next_entry = tp->cur_rx;
/* If frame length is greater than skb buffer size
(preallocated during init) then the packet is ignored */
int frame_len = get_rx_frame_len(tp);
if (frame_len > tp->dma_buf_sz) {
printk("len %d larger than size (%d)\n", frame_len, tp->dma_buf_sz);
continue;
}
struct sk_buff *skb = tp->rx_skbuff[entry];
if (unlikely(!skb)) {
printk("Inconsistent Rx chain\n");
continue;
}
prefetch(skb->data - NET_IP_ALIGN);
tp->rx_skbuff[entry] = NULL;
skb_put(skb, frame_len);
dma_unmap_single(tp->device, tp->rx_skbuff_dma[entry],
tp->dma_buf_sz, DMA_FROM_DEVICE);
/* from this point it is safe to access the data of the rx skb.
the DMA transaction is already complete
and the rx buffer is unmapped from the DMA */
netif_receive_skb(skb);
}
rx_refill(dev);
return count;
}
Prepare the Rx buffers for the next DMA transactions
static inline void rx_refill(struct net_device *dev)
{
struct my_private *tp = (struct my_private *)dev->priv;
int dirty = get_num_of_rx_dirty(tp);
unsigned int entry = tp->dirty_rx;
while (dirty-- > 0) {
if (likely(!tp->rx_skbuff[entry])) {
struct sk_buff *skb;
skb = netdev_alloc_skb_ip_align(dev, tp->dma_buf_sz);
if (unlikely(!skb)) {
printk("fail to alloc skb entry %d\n", entry);
break;
}
rx_q->rx_skbuff[entry] = skb;
rx_q->rx_skbuff_dma[entry] = dma_map_single(tp->device, skb->data,
tp->dma_buf_sz, DMA_FROM_DEVICE);
if (dma_mapping_error(tp->device, tp->rx_skbuff_dma[entry])) {
printk("Rx DMA map failed\n");
dev_kfree_skb(skb);
break;
}
}
entry = get_rx_entry(entry, DMA_RX_SIZE);
}
tp->dirty_rx = entry;
}
Free the Rx Buffers
static void free_rx_buffer(struct net_device *dev, int i)
{
struct my_private *tp = (struct my_private *)dev->priv;
if (tp->rx_skbuff[i]) {
dma_unmap_single(tp->device, tp->rx_skbuff_dma[i],
tp->dma_buf_sz, DMA_FROM_DEVICE);
dev_kfree_skb_any(tp->rx_skbuff[i]);
}
tp->rx_skbuff[i] = NULL;
}