GPIO poll exits immediately - c

I need to free the processor while I wait for a change in the level of a GPIO pin (either rising or falling edge), so I created a simple code to poll a GPIO sysfs value file, but I'm running into some trouble:
In the first poll() call, it exits imediatelly, with both POLLPRI and POLLERR set in revents;
After this, I lseek() and read() the fd, and loop back to poll();
Now poll() hangs.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/fcntl.h>
#define GPIO_DIR "/sys/class/gpio/"
#define GPIO_EXPORT GPIO_DIR "export"
int main(int argc, char **argv)
{
int gpio_fd;
struct pollfd gpio_fdset[1];
char pin_value[] = GPIO_DIR "gpioXYZ/value";
sprintf(pin_value, GPIO_DIR "gpio%s/value", argv[1]);
gpio_fd = open(pin_value, O_RDONLY);
while (1)
{
char buffer[64];
gpio_fdset[0].fd = gpio_fd;
gpio_fdset[0].events = POLLPRI;
gpio_fdset[0].revents = 0;
poll(gpio_fdset, 1, -1);
if (gpio_fdset[0].revents & POLLPRI)
{
printf("revents returned POLLPRI!\n");
lseek(gpio_fdset[0].fd, 0, SEEK_SET);
read(gpio_fdset[0].fd, buffer, 64);
}
}
}
Before calling it, I export the pin I wish to monitor (GPIO1_30 or 62 in the kernel numbering scheme). I've tried setting this pin as input, output, generating interrupts on rising and falling edges, but the behaviour is always the same. What am I missing?
From what I've read, when I use the sysfs, I should not need to use the gpio_request(), gpio_to_irq() and other related functions to be able to poll this pin. Is this right?
Regards,
Guilherme

I've discovered how to overcome this issue. Simply perform a dummy read() after setting opening the file descriptor. Apparently this is due to the fact that a recently opened fd is considered as changed (at least for GPIOs). As for the POLLERR on revents, this is standard sysfs behaviour.

If I understand your requirement right, then you want to take some action when the pin goes high.
you can poll the pin in application layer it self.
Download the "SimpleGPIO.h" and "SimpleGPIO.cpp" from the below URL:
https://github.com/derekmolloy/beaglebone
The SimpleGPIO.h/cpp is self explanatory and you can do all operations with GPIO using the simple function calls.
This one will work fine for any am335x processor. Then to poll you can use in your code some thing like this
int main()
{
//Your code
while(1)
{
if(gpio_get_value())
{
//Do what ever you want to do.
}
}
}
NOTE::
If you want to send any signal to your application process from kernel level using irq then the approach will be little different, But only for polling this code will work fine.
Hope this helps.
Edit:
Please refer below url for more details, it explains your question. You need to use any signal between (Signal number 32 to 64) to detect the change of GPIO status. You need to register your processId with your kernel module.
http://yongbingchen.github.io/blog/2013/03/11/sending-a-signal-from-linux-kernel/
When there is a change in GPIO status, Kernel sends a signal to application layer on which a dedicated function in application layer can execute.

Related

Weirdness using the raspberry pi pico uart with the c sdk

I am extremely disconcerted.
I'm making a remote controlled machine using a pi pico to drive the motors and read some sensors, and a raspberry pi 4 to send commands to the pi pico via serial and host the web interface.
The following code seems to work... but... If I remove the if with uart_is_writable coding and its content it doesn't work. Does anyone have any idea why?
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
//DEFINES
#define UART_ID uart0
#define BAUD_RATE 19200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN
static int chars_rxed = 0;
volatile char uCommand[32] = {0, 0};
void on_uart_rx(void) {
char tmp_string[] = {0, 0};
new_command = true;
while (uart_is_readable(UART_ID)) {
uint8_t ch = uart_getc(UART_ID);
tmp_string[0] = ch;
strcat(uCommand, tmp_string);
if(uart_is_writable(UART_ID)){
uart_putc(UART_ID, '-');
uart_puts(UART_ID, uCommand);
uart_putc(UART_ID, '-');
}
chars_rxed++;
}
}
int main(){
uart_init(UART_ID, BAUD_RATE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
uart_set_hw_flow(UART_ID, false, false);
uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
uart_set_fifo_enabled(UART_ID, false);
int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;
irq_set_exclusive_handler(UART_IRQ, on_uart_rx);
irq_set_enabled(UART_IRQ, true);
uart_set_irq_enables(UART_ID, true, false);
uart_puts(UART_ID, "\nOK\n");
while (1){
tight_loop_contents();
if(uCommand[0] != 0){
uart_putc(UART_ID, '/');
uart_puts(UART_ID, uCommand);
memset(uCommand, 0, sizeof(uCommand));
}
}
}
The example code you linked to is for a simple tty/echo implementation.
You'll need to tweak it for your use case.
Because Tx interrupts are disabled, all output to the transmitter has to be polled I/O. Also, the FIFOs in the uart are disabled, so only single char I/O is used.
Hence, the uart_is_writable to check whether a char can be transmitted.
The linked code ...
echos back the received char in the Rx ISR. So, it needs to call the above function. Note that if Tx is not ready (i.e. full), the char is not echoed and is dropped.
I don't know whether uart_putc and uart_puts check for ready-to-transmit in this manner.
So, I'll assume that they do not.
This means that if you call uart_putc/uart_puts and the Tx is full, the current/pending char in the uart may get trashed/corrupted.
So, uart_is_writable should be called for any/each char to be sent.
Or ... uart_putc/uart_puts do check and will block until space is available in the uart Tx fifo. For you use case, such blocking is not desirable.
What you want ...
Side note: I have done similar [product/commercial grade] programming on an RPi for motor control via a uart, so some of this is from my own experience.
For your use case, you do not want to echo the received char. You want to append it to a receive buffer.
To implement this, you probably want to use ring queues: one for received chars and one for chars to be transmitted.
I assume you have [or will have] devised some sort of simple packet protocol to send/receive commands. The Rpi sends commands that are (e.g.):
Set motor speed
Get current sensor data
The other side should respond to these commands and execute the desired action or return the desired data.
Both processors probably need to have similar service loops and ISRs.
The Rx ISR just checks for space available in the Rx ring queue. If space is available, it gets a char from the uart and enqueues it. If no Rx char is available in the uart, the ISR may exit.
The base level code service loop should:
Check if the uart Tx can accept another character (via uart_is_writable) and, if so, it can dequeue a char from the Tx ring queue [if available] and send it (via uart_putc). It can loop on this to keep the uart transmitter busy.
Check to see if enough chars are received to form a packet/message from the other side. If there is such a packet, it can service the "request" contained in it [dequeueing the chars to make more space in the Rx ring queue].
If the base level needs to send a message, it should enqueue it to the Tx ring queue. It will be sent [eventually] in the prior step.
Some additional thoughts ...
The linked code only enables Rx interrupts and runs the Tx in polled mode. This may be enough. But, for maximum throughput and lowest latency, you may want to make the Tx interrupt driven as well.
You may also wish the enable the FIFOs in the uart so you can queue up multiple characters. This can reduce the number of calls to the ISR and provide better throughput/latency because the service loop doesn't have to poll so often.

Receive UART messages via Cooja on a Z1 mote

I'm currently developing a contiki programm that runs on a Z1 device for debugging purposes. I would like to send UART messages to that device and found out that Cooja appears to supports that with a function called "Show serial port on Z1". That tool in fact helped me to read UART messages sent from the mote, but when I try to send somethin back, the Int handler just doesn't get called.
Here's how I initialize UART in code:
uart0_init(0);
uart0_set_input(uart_handler);
uart0_writeb('U');
In the handler itself, I just toggle all LEDs (which definitely works) - however, they never get toggled. I even tried to send a byte in the ISR handler within the uart0-library but even that byte never gets sent. This means that the whole UART communication between Cooja and the Z1 mote does not seem to work correctly. Has anyone ever had the same problem and is able to provide me with a solution for that? It would be a great help!
I did manage to figure it out in the mean time. Here's the solution for anybody who is facing the same problem.
The following code works. Depending on whether you define USE_SERIAL_LINE you can decide if you would like to use the serial-line-module or your own int handler.
#include <stdio.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "dev/uart0.h"
#define USE_SERIAL_LINE
#ifdef USE_SERIAL_LINE
#include "dev/serial-line.h"
#endif
PROCESS(init_system_proc, "Init system process");
AUTOSTART_PROCESSES(&init_system_proc);
int uart_handler(unsigned char c){
printf("Single Byte input.\n");
return 1;
}
PROCESS_THREAD(init_system_proc, ev, data){
PROCESS_BEGIN();
uart0_init(0);
#ifdef USE_SERIAL_LINE
serial_line_init();
uart0_set_input(serial_line_input_byte);
#else
uart0_set_input(uart_handler);
#endif
while (1) {
PROCESS_YIELD();
#ifdef USE_SERIAL_LINE
if(ev == serial_line_event_message)
printf("Serial input.\n");
#endif
}
PROCESS_END();
}
There's one thing you need to keep in mind when using printf for UART output. A UART message will only be send when "\n" appears - this means that every printf-statement should end with a new line character. Otherwise your string only gets buffered and send out once a new line character appears.

Correct way to block read operations until an external event?

I am working on a devices driver for a data acquisition system. There is a pci device that provides input and output data at the same time at regular intervals. And then the linux mod manages the data in circular buffers that are read and written to through file operations.
The data throughput of the system is relatively low it receives just over 750,000 bytes/second and transmits just over 150,000 bytes per second.
There is a small user space utility that writes and reads data in a loop for testing purposes.
Here is a section of the driver code (All the code related to the circular buffers has been omitted for simplicity sake. PCI device initialization is taken care of elsewhere and pci_interupt not the real entry point for the interrupt handler)
#include <linux/sched.h>
#include <linux/wait.h>
static DECLARE_WAIT_QUEUE_HEAD(wq_head);
static ssize_t read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
DECLARE_WAITQUEUE(wq, current);
if(count == 0)
return 0;
add_wait_queue(&wq_head, &wq);
do
{
set_current_state(TASK_INTERRUPTIBLE);
if(/*There is any data in the receive buffer*/)
{
/*Copy Data from the receive buffer into user space*/
break;
}
schedule();
} while(1);
set_current_state(TASK_RUNNING);
remove_wait_queue(&wq_head, &wq);
return count;
}
static ssize_t write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
/* Copy data from userspace into the transmit buffer*/
}
/* This procedure get's called in real time roughly once every 5 milliseconds,
It writes 4k to the receiving buffer and reads 1k from the transmit buffer*/
static void pci_interrupt() {
/*Copy data from PCI dma buffer to receiving buffer*/
if(/*There is enough data in the transmit buffer to fill the PCI dma buffer*/) {
/*Copy from the transmit buffer to the PCI device*/
} else {
/*Copy zero's to the PCI device*/
printk(KERN_ALERT DEVICE_NAME ": Data Underflow. Writing 0's'");
}
wake_up_interruptible(&wq_head);
}
The above code works well for long periods of time however every 12-18 hours there is a data underflow error. Resulting in zeros being written.
My first thought is that due to the userspace application not being truly real-time the time delay between it's read and write operations occasionally got too large causing the failure. However I tried changing the size of the reads and writes in userspace and changing the niceness of the userspace application this had no effect on the frequency of the error.
Do to the error's nature I believe there is some form of race condition in the three methods above. I am not sure how linux kernel wait queues work.
Is there a decent alternative to the above method for blocking reads or is there something else that is wrong the could cause this behavior.
System Information:
Linux Version: Ubuntu 16.10
Linux Kernel: linux-4.8.0-lowlatency
Chipset: Intel Celeron N3150/N3160 Quad Core 2.08 GHz SoC
TL;DR: The above code hits underflow errors every 12-18 hours is there a better way to do blocking IO or some race condition in the code.
One standard way used in linux can also be used in your case.
User space test program:
1. open file in blocking mode (default in linux until you specify NONBLOCK flag)
2. call select() to block on file descriptor.
Kernel driver:
1. Register interrupt handler which gets invoked whenever there is data available
2. Handler take lock to protect common buffer between reads/writes and transfer of data
Take a look at these links for source code from ldd3 book test and driver.

Debian I2C driver for OLED screen not working. [ssd1306]

I have some driver code that I am testing out for use with an SSD1306 driven OLED screen which is 128x32 (same as the OLED adafruit model). I need this to run in debian (I am using Linario-4.4.9)
I have followed the Debian guides on how to start creating a file handler for the device, this can be seen as follows below. The only thing in oled.h is the device adress (0x3C) and the proto types. I followed the initialization approach taken on the adafruit github (as I tried their code out first on an Ardunio to ensure the screen does in fact work). I believe I may be doing something wrong but I'm not entirely sure what I am doing wrong. I have also listed my init process below.
#include <errno.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/i2c-dev.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "oled.h"
int oled;
int lcd_driver_init(void)
{
///< Begin the init proc.
int dloc = open("/dev/i2c-1", O_RDWR);
if (dloc < 0 )
{
fprintf(stderr, "Error opening i2c device\n");
return -1;
}
if(ioctl(dloc, I2C_SLAVE, SCR_ADDR) < 0)
{
fprintf(stderr, "Error in ioctl. Errno :%i\n",errno);
return -2;
}
oled = dloc;
fprintf(stderr, "init success, device open and local\n");
return EXIT_SUCCESS;
}
int oled_command( uint8_t cmd)
{
char command[2]= {0};
command[1] = cmd;
int check = (write(oled, command, 2));
return check;
}
void oled_cmd_start()
{
int check = (write(oled, 0x00, sizeof(uint8_t)));
if(check<0)
fprintf(stderr, "Errno set:: %i\n", errno);
return;
}
void oled_data_start()
{
uint8_t _data_start_[1] ={ 0x40 };
int check = (write(oled, _data_start_, sizeof(uint8_t)));
if(check<0)
fprintf(stderr, "Errno set oled_data_start:: %i\n", errno);
return;
}
int oled_data (uint8_t xmit)
{
int check = (write(oled, &xmit, (sizeof(uint8_t))));
if(check<0)
fprintf(stderr, "Errno set oled_data:: %i\n", errno);
return check;
}
INIT PROCESS
void sendcommand(unsigned char payload)
{
oled_data(0x00); //Control Byte - Command
oled_data(payload); //payload
}
void lcd_init(void)
{
sendcommand(0xAE);//--Set Display off
sendcommand(0x00);//--set low column address
sendcommand(0x10);//--set high column address
sendcommand(0x81);//--set contrast control register
sendcommand(0x7f);
sendcommand(0xa1);//--set segment re-map 95 to 0
sendcommand(0xA6);//--set normal display
sendcommand(0xa8);//--set multiplex ratio(1 to 16)
sendcommand(0x1f);//--duty 1/32
sendcommand(0xd3);//--set display offset
sendcommand(0x00);//--not offset
sendcommand(0xd5);//--set display clock divide ratio/oscillator frequency
sendcommand(0xf0);//--set divide ratio
sendcommand(0xd9);//--set pre-charge period
sendcommand(0x22);
sendcommand(0xda);//--set com pins hardware configuration
sendcommand(0x02);//disable left/right remap and set for sequential
sendcommand(0xdb);//--set vcomh
sendcommand(0x49);//--0.83*vref
sendcommand(0x8d);//--set DC-DC enable
sendcommand(0x14);//
sendcommand(0xAF);//--turn on oled panel
sendcommand(0xA4);//--Entire Display ON
}
Following this, I send alternating 0xFF to try and make stripes on the screen. The only thing that shows up is random pixels. Nothing coherent.
I have connected a logic analyzer to sniff the I2C lines, and it appears that when I have the LA connected, the I2C lines no longer function and ERRNO returns an IO fault (#5).
There doesn't ever seem to be an issue opening up the device to get the file pointer however.
I do get ERRNO as timeout sometimes, but I have read that this is just an issue with I2C devices using the protocal as write expects a quicker response than I2C might give.
I am also compiling with -std=c99 -O0 to ensure all of the inline functions are there as well as ensuring that loop variables are available.
If anyone can point me in the right direction of can point out some flaw in my approach it would be much appreciated. Thank you.
EDIT
I've checked the device tree and the i2c device is correctly enabled. However none of the i2c_freq speeds seem to be enabled. Could this be causing the timeouts and the garbage data transfer?
I have connected a logic analyzer to sniff the I2C lines, and it appears that when I have the LA connected, the I2C lines no longer function and ERRNO returns an IO fault (#5).
logic analyzer is just a device for measurement. It converts the captured data into timing diagrams, decodes protocol which you have set. So it will not be responsible for any I2C read write error (until your grounding and h/w connections are correct).
For timeout issue either you can try by decreasing the i2c clock-frequency or ioctl I2C_TIMEOUT.
It turns out the SOM has an internal regulator for the I2C lines to be 1V8 where as the SSD1306 chip is running at 3V3 causing information to be mishandled. This behavior wasn't documented on the SOM.
Applying a level shifting chip to the design allowed for proper communication.
If someone has this same problem, check your schematics for voltage mismatch levels.

AT commands in embedded systems

I am using embedded C and trying to make application for GPRS terminal. My main problem is working with AT commands. I send AT command using serial line, but if it is some network oriented command its response could take time and because of that I have a lot of waiting, while processor don`t do anything. Idea is to make this waiting to be done in same way parallel like in different thread. Does anyone have idea how to do that because my system does not support threads?
I had idea to use some timers, because we have interrupt which is called every 5ms, but I don't know ho many seconds I have to wait for response, and if I compare strings in interrupt to check if all message is received it could be very inefficient, right?
you could either use interrupts, configure the serial interface to interrupt when data is available, or use an RTOS something, like FreeRTOS, to run two threads, one for the main code and the other to block and wait for the serial data.
Update: based on your comments, you say you don't know the size of the data, that's fine, in the interrupt handler check for the byte that terminates the data, this is a simple and generic example you should check the examples for your MCU:
void on_serial_char()
{
//disable interrupts
disable_interrupts();
//read byte
byte = serial.read();
//check if it's the terminating byte
if (byte == END) {
//set the flag here
MESSAGE_COMPLETE = 1;
}
//add byte to buffer
buf[length++] = byte;
//enable interrupts
enable_interrupts();
}
And check for that flag in your main loop:
...
if (MESSAGE_COMPLETE) {
//process data
...
//you may want to clear the flag here
MESSAGE_COMPLETE = 0;
//send next command
...
}
You can simply call a packetHandler in each mainLoopCycle.
This handler checks if new characters are available from the serial port.
The packetHandler will build the response message bit for bit, if the message is complete (CR LF found) then it calls a messageReceive function, else it simply returns to the mainLoop.
int main()
{
init();
for (;;)
{
packetHandler();
}
}
char msgBuffer[80];
int pos=0;
void packetHandler()
{
char ch;
while ( isCharAvailable() )
{
ch=getChar();
msgBuffer[pos++] = ch;
if ( ch == '\n' )
{
messageReceived(msgBuffer);
pos=0;
}
}
}
It sounds like you are rather close to the hardware drivers. If so, the best way is to use DMA, if the MCU supports it, then use the flag from the DMA hardware to determine when to start parse out the received data.
The second best option is to use rx interrupts, store every received byte in a simple FIFO, such as a circular buffer, then set some flag once you have received them. One buffer for incoming data and one for the latest valid data received may be necessary.

Resources