Reading and writing on I/O ports - c

I am trying to understand the following code:
#include<stdio.h>
#include<stdlib.h>
#include<sys/io.h>
#define baseport 0x378
int main()
{
int b;
if(ioperm(baseport,3,1))
{
perror("ioperm");
exit(1);
}
outb(0,baseport);
usleep(1000000);
printf("\n the status: %x,\n",inb(baseport));
if (ioperm(baseport,3,0)) {perror("ioperm"); exit(1);}
exit(0);
}
The output is 0xff, 255 in decimal, whether I write on Port 1 or Port 0 (using outb()). I cannot understand why it is 255 when I am writing 0 to it.

The result of doing inb(0x378) is hardware-dependent. Some chips return the value you have written previously with outb, and some other chips just return garbage. In any case, it is not the port to read bytes from a potentially connected device.

First you need to see the port's capabilities, input, output or both. If it can be configured as both, you have to set it to the respective mode and only then you can expect the right behavior.

Related

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.

init, read and write for linux serial device with C

I'm working on a new project where I want to make a connection with an FTDI which is connected to my debian machine. I am intending to write the code with C, not C++. Here lies my problem. All the examples I find are incomplete or are made for a c++ compiler in stead of the GCC compiler.
The goal is to talk to my microcontroller which is connected to the FTDI. For debugging i want to start building a linux application which is able to:
initialize a serial connection on startup with ttyUSB1
send a character string
display character strings when they are received by the pc
save the communication to a .txt file
Is there any example code or tutorial to make this?
If I succeed I will defenetly place the code here so that new viewers can use it to!
Edit:
Like I said I would post the code if I had it, and this is what worked for me:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#define MODEM "/dev/ttyUSB0"
#define BAUDRATE B115200
int main(int argc,char** argv)
{
struct termios tio;
struct termios stdio;
struct termios old_stdio;
int tty_fd, flags;
unsigned char c='D';
tcgetattr(STDOUT_FILENO,&old_stdio);
printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
memset(&stdio,0,sizeof(stdio));
stdio.c_iflag=0;
stdio.c_oflag=0;
stdio.c_cflag=0;
stdio.c_lflag=0;
stdio.c_cc[VMIN]=1;
stdio.c_cc[VTIME]=0;
tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make the reads non-blocking
memset(&tio,0,sizeof(tio));
tio.c_iflag=0;
tio.c_oflag=0;
tio.c_cflag=CS8|CREAD|CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=5;
if((tty_fd = open(MODEM , O_RDWR | O_NONBLOCK)) == -1){
printf("Error while opening\n"); // Just if you want user interface error control
return -1;
}
cfsetospeed(&tio,BAUDRATE);
cfsetispeed(&tio,BAUDRATE); // baudrate is declarated above
tcsetattr(tty_fd,TCSANOW,&tio);
while (c!='q'){
if (read(tty_fd,&c,1)>0){
write(STDOUT_FILENO,&c,1); // if new data is available on the serial port, print it out
printf("\n");
}
if (read(STDIN_FILENO,&c,1)>0){
write(tty_fd,&c,1);//if new data is available on the console, send it to serial port
printf("\n");
}
}
close(tty_fd);
tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);
return EXIT_SUCCESS;
}
Most of the code came from http://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux but i also used a bit from the code posted below.
Handling with serial ports ( for linux OS ) :
- To open communication, you will need a descriptor which will be the handle for your serial port.
- Set the flags to control how the comunication will be.
- Write the command to this Handle ( make sure you're formatting the input correctly ).
- Get the answer. (make sure you're to read the amount of information you want )
- Close the handle.
It will seem like this:
int fd; // file descriptor
int flags; // communication flags
int rsl_len; // result size
char message[128]; // message to send, you can even dinamically alocate.
char result[128]; // result to read, same from above, thanks to #Lu
flags = O_RDWR | O_NOCTTY; // Read and write, and make the job control for portability
if ((fd = open("/dev/ttyUSB1", flags)) == -1 ) {
printf("Error while opening\n"); // Just if you want user interface error control
return -1;
}
// In this point your communication is already estabilished, lets send out something
strcpy(message, "Hello");
if (rsl_len = write(fd, message, strlen(message)) < 0 ) {
printf("Error while sending message\n"); // Again just in case
return -2;
}
if (rsl_len = read(fd, &result, sizeof(result)) < 0 ) {
printf("Error while reading return\n");
return -3;
}
close(fd);
Note that you have to care about what to write and what to read.
Some more flags can be used in case of parity control, stop bits, baud rate and more.
Since gcc is a C/C++ compiler, you don't need to limit yourself to pure C.
Sticking to pure C is OK if you enjoy writing lots of boilerplate code, and if you really know what you're doing. Many people use Unix APIs incorrectly, and a lot of example code out there is much too simplistic. Writing correct Unix C code is somewhat annoying, to say the least.
Personally, I'd suggest using not only C++, but also a higher-level application development framework like Qt. Qt 5 comes bundled with a QtSerialPort module that makes it easy to enumerate the serial ports, configure them, and get data into and out of them. Qt does not force you to use the gui modules, it can be a command line application, or a non-interactive server/daemon.
QtSerialPort is also usable from Qt 4, but it doesn't come bundled with Qt 4, you have to add it to your project. I suggest starting out with Qt 5, it's nicer to use with its C++11 support.
The code using Qt can be pretty simple, not much longer than your plain-English description. The below is a Qt console application using Qt 5 and C++11. It uses the core and serialport modules. It also handles the SIGINT signal so that the output file gets flushed before the process would terminate due to a ^C. I'm using QLocalSocket in place of raw Unix API to communicate from the Unix signal handler, the functionality is the same.
Only the code within main is strictly required, the rest is just to make it properly wrap things up when you hit ^C.
#include <QCoreApplication>
#include <QSerialPort>
#include <QFile>
#include <QTextStream>
#include <QLocalServer>
#include <QLocalSocket>
#include <cstdio>
#include <csignal>
QLocalSocket * xmit;
static void signalHandler(int)
{
xmit->write(" ");
xmit->flush();
}
static bool setupSignalHandler()
{
QLocalServer srv;
srv.listen("foobarbaz");
xmit = new QLocalSocket(qApp);
xmit->connectToServer(srv.serverName(), QIODevice::WriteOnly);
srv.waitForNewConnection();
QLocalSocket * receive = srv.nextPendingConnection();
receive->setParent(qApp);
qApp->connect(receive, &QLocalSocket::readyRead, &QCoreApplication::quit);
struct sigaction sig;
sig.sa_handler = signalHandler;
sigemptyset(&sig.sa_mask);
sig.sa_flags = SA_RESTART;
return ! sigaction(SIGINT, &sig, NULL);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
setupSignalHandler();
QSerialPort port("ttyUSB1");
QFile file("file.txt");
QTextStream err(stderr, QIODevice::WriteOnly);
QTextStream out(stdout, QIODevice::WriteOnly);
if (!file.open(QIODevice::WriteOnly)) {
err << "Couldn't open the output file" << endl;
return 1;
}
if (!port.open(QIODevice::ReadWrite)) {
err << "Couldn't open the port" << endl;
return 2;
}
port.setBaudRate(9600);
QObject::connect(&port, &QSerialPort::readyRead, [&](){
QByteArray data = port.readAll();
out << data;
file.write(data);
});
out << "Use ^C to quit" << endl;
return a.exec();
}

What causes a segmentation fault on a call to inb_p()?

I am getting a segmentation fault when trying to read a port with inb_p( ). I'm compiling this on a Debian system running 2.6.6 kernel on an Intel D525 dual-core system (Advantech PCM 9389 SBC). Here is a sample program which illustrates the segfault.
What is the probable cause? How do I fix this?
Currently, I don't have any devices hooked up. Could this cause the segfault? I would have expected to get either a zero or some random byte, but not a segfault.
Other things I tried:
1) Declared the input variable as int instead of char.
2) Used iopl() instead of ioperm()
/*
* ioexample.c: very simple ioexample of port I/O
* very simple port i/o
* Compile with `gcc -O2 -o ioexample ioexample.c',
* and run as root with `./ioexample'.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/io.h>
#define BASEPORT 0x0100 /* iobase for sample system */
#define FLIPC 0x01
#define FLIPST 0x0
#define DIPSWITCH 0x25
int main()
{
char cinput;
cinput = 0xff;
setuid(0);
printf("begin\n");
/* Get access to the ports */
if (ioperm(BASEPORT+DIPSWITCH, 10, 1))
{
perror("ioperm");
exit(EXIT_FAILURE);
}
printf("read the dipswitch with pause\n");
cinput = inb_p(BASEPORT+DIPSWITCH); // <=====SEGFAULT HERE
/* We don't need the ports anymore */
if (ioperm(BASEPORT+DIPSWITCH, 10, 0))
{
perror("ioperm");
exit(EXIT_FAILURE);
}
printf("Dipswitch setting: 0x%X", cinput);
exit(EXIT_SUCCESS);
}
/* end of ioexample.c */
Output:
root#debian:/home/howard/sources# ./ioexample
begin
read the dipswitch with pause
Segmentation fault
Edit: /proc/ioports did not list anything at address 0x100, so I tried several other port addresses that were listed, with the same result. Then I decided to try an output to a known parallel port location (0x0378), and outb did not cause a segfault. However, trying to read either 0x378 or 0x379 did cause a segfault. I am beginning to suspect that the problem is hardware related.
I found the problem. The call to inb_p() requires access to port 0x80 in addition to the port to be read.
Apparently, when I tried iopl(), I didn't call it correctly, because that should have worked.
The following code eliminated the segfault:
/* Get access to the ports */
if (ioperm(0x80, 1, 1))
{
perror("ioperm");
exit(EXIT_FAILURE);
}
if (ioperm(BASEPORT+DIPSWITCH, 10, 1))
{
perror("ioperm");
exit(EXIT_FAILURE);
}

Issue in pcap_set_buffer_size()

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#define BUFFER_SIZE 65535
char errbuf[PCAP_ERRBUF_SIZE];
int main(int argc, char **argv)
{
int d;
pcap_if_t *alldevsp;
pcap_t *pkt_handle;
if((pcap_findalldevs(&alldevsp,errbuf))==-1)
{
printf("findalldevices: %s\n",errbuf);
exit(1);
}
printf("Availabel network devices are\n");
pcap_if_t *temp = alldevsp;
while((temp)!=NULL)
{
printf("%s: %s\n",(temp)->name,(temp)->description);
(temp)=(temp)->next;
}
pcap_freealldevs(alldevsp);
pkt_handle = pcap_create("wlan1",errbuf);
if(pkt_handle==NULL)
{
printf("create: %s\n",errbuf);
exit(1);
}
if((pcap_set_rfmon(pkt_handle, 1))!=0)
{
printf("Monitor mode could not be set\n");
exit(1);
}
if((pcap_set_buffer_size(pkt_handle, BUFFER_SIZE))!=0)
{
printf("ERROR\n");
exit(1);
}
if((d=(pcap_activate(pkt_handle)))!=0)
{
if(d==PCAP_ERROR_RFMON_NOTSUP)
printf("%d : PCAP_ERROR_RFMON_NOTSUP\n",d);
if(d==PCAP_WARNING)
printf("%d : PCAP_WARNING\n",d);
if(d==PCAP_ERROR)
printf("%d : PCAP_ERROR\n",d);
pcap_perror(pkt_handle,"Activate");
exit(1);
}
printf("d=%d\n",d);
while(1)
{
scanf("%d",&d);
if(d==-1)
break;
}
pcap_close(pkt_handle);
printf("Bye\n");
return 0;
}
When you run the above program using:
gcc -Wall -lpcap sample.c -o sample
I get the follwing error:
-1 : PCAP_ERROR
Activate: can't mmap rx ring: Invalid argument
However, if I comment out the section of code containing pcap_set_buffer_size() function call, the program works perfectly fine.
So, what is this problem with pcap_set_buffer_size()?
Why is it causing pcap_activate() to fail?
For a recent 64bit Linux:
Any buffer size equal or larger then 65616 should do.
For how the value is calculated please see the implementation of create_ring() in pcap-linux.c from the libpcap sources.
The default is 2*1024*1024 = 2097152.
The default buffer size on windows is 1000000.
Update:
The buffer size to be set by pcap_set_buffer_size() refers to the (ring-)buffer, which stores the already received packages. The optimal size depends on the use case and on the affordable system resources (non-pageable memory).
Please see the following statements on the receive buffer's size verbatim from man pcap:
Packets that arrive for a capture are stored in a buffer, so that they
do not have to be read by the application as soon as they arrive. On
some platforms, the
buffer's size can be set; a size that's too small could mean that, if too many packets are being captured and the
snapshot length doesn't limit the amount of
data that's buffered, packets could be dropped if the buffer fills up before the application can read packets from it, while
a size that's too large could use
more non-pageable operating system memory than is necessary to prevent packets from being dropped.
Update 1:
Anyway, the buffer's size should be least the snap length set for the handle in use, plus some bytes needed to properly align the buffer itself, otherwise activating the handle ends up as described in the original question.
One can retrieve the handle's current snap length using pcap_snapshot(). The default snap length is 65535 bytes.

Reading / writing from using I2C on Linux

I'm trying to read/write to a FM24CL64-GTR FRAM chip that is connected over a I2C bus on address 0b 1010 011.
When I'm trying to write 3 bytes (data address 2 bytes, + data one byte), I get a kernel message ([12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout.), as well as the write returns != 3. See code below:
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
int file;
char filename[20];
int addr = 0x53; // 0b1010011; /* The I2C address */
uint16_t dataAddr = 0x1234;
uint8_t val = 0x5c;
uint8_t buf[3];
sprintf(filename,"/dev/i2c-%d",0);
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
buf[0] = dataAddr >> 8;
buf[1] = dataAddr & 0xff;
buf[2] = val;
if (write(file, buf, 3) != 3)
exit(3);
...
However when I write 2 bytes, then write another byte, I get no kernel error, but when trying to read from the FRAM, I always get back 0. Here is the code to read from the FRAM:
uint8_t val;
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
if (write(file, &dataAddr, 2) != 2) {
exit(3);
if (read(file, &val, 1) != 1) {
exit(3);
None of the functions return an error value, and I have also tried it with:
#include <linux/i2c.h>
struct i2c_rdwr_ioctl_data work_queue;
struct i2c_msg msg[2];
uint8_t ret;
work_queue.nmsgs = 2;
work_queue.msgs = msg;
work_queue.msgs[0].addr = addr;
work_queue.msgs[0].len = 2;
work_queue.msgs[0].flags = 0;
work_queue.msgs[0].buf = &dataAddr;
work_queue.msgs[1].addr = addr;
work_queue.msgs[1].len = 1;
work_queue.msgs[1].flags = I2C_M_RD;
work_queue.msgs[1].buf = &ret;
if (ioctl(file,I2C_RDWR,&work_queue) < 0)
exit(3);
Which also succeeds, but always returns 0. Does this indicate a hardware issue, or am I doing something wrong?
Are there any FRAM drivers for FM24CL64-GTR over I2C on Linux, and what would the API be? Any link would be helpful.
I do not have experience with that particular device, but in our experience many I2C devices have "quirks" that require a work-around, typically above the driver level.
We use linux (CELinux) and an I2C device driver with Linux as well. But our application code also has a non-trivial I2C module that contains all the work-around intelligence for dealing with all the various devices we have experience with.
Also, when dealing with I2C issues, I often find that I need to re-acquaint myself with the source spec:
http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
as well as the usage of a decent oscilloscope.
Good luck,
Above link is dead, here are some other links:
http://www.nxp.com/documents/user_manual/UM10204.pdf
and of course wikipedia:
http://en.wikipedia.org/wiki/I%C2%B2C
The NAK was a big hint: the WriteProtect pin was externally pulled up, and had to be driven to ground, after that a single write of the address followed by data-bytes is successful (first code segment).
For reading the address can be written out first (using write()), and then sequential data can be read starting from that address.
Note that the method using the struct i2c_rdwr_ioctl_data and the struct i2c_msg (that is, the last code part you've given) is more efficient than the other ones, since with that method you execute the repeated start feature of I2c.
This means you avoid a STA-WRITE-STO -> STA-READ-<data>...-STO transition, because your communication will become STA-WRITE-RS-READ-<data>...STO (RS = repeated start). So, saves you a redundant STO-STA transient.
Not that it differs a lot in time, but if it's not needed, why losing on it...
Just my 2 ct.
Best rgds,
You had some mistakes!
The address of ic is Ax in hex, x can be anything but the 4 upper bits should be A=1010 !!!

Resources