I'm using a pc1602f PowerTip directly connected to the PC parallel port using this scheme:
http://www.beyondlogic.org/parlcd/parlcd.htm
All well as energizes the LCD and shows me the front row with black blocks, until then fine but now I want to send information through the parallel port.
If you look at the page you will see that there is a source to send information to the lcd, but uses windows libraries: huh:
I leave my code attempted to become linux.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#define PORTADDRESS 0x3f8
#define DATA PORTADDRESS+0
#define STATUS PORTADDRESS+1
#define CONTROL PORTADDRESS+2
main(int argc, char **argv)
{char string[] = {"Testing 1,2,3"};
int count;
int len;
char init[10];
init[0] = 0x0F; /* Init Display */
init[1] = 0x01; /* Clear Display */
init[2] = 0x38; /* Dual Line / 8 Bits */
if (ioperm(PORTADDRESS,1,1))
fprintf(stderr, "No se puede acceder al: %x\n", PORTADDRESS), exit(1);
outb(CONTROL, inb(CONTROL) & 0xDF);
outb(CONTROL, inb(CONTROL) & 0x08);
for (count = 0; count <= 2; count++)
{
outb(DATA, init[count]);
outb(CONTROL,inb(CONTROL) | 0x01);
sleep(20);
outb(CONTROL,inb(CONTROL) & 0xFE);
sleep(20);
}
outb(CONTROL, inb(CONTROL) & 0xF7);
len = strlen(string);
for (count = 0; count < len; count++)
{
outb(DATA, string[count]);
outb(CONTROL,inb(CONTROL) | 0x01);
sleep(2);
outb(CONTROL,inb(CONTROL) & 0xFE);
sleep(2);
}
}
Compiles perfectly but when I want to try it as root and run it throws me
root#ubuntu: /
media/E80C-30D5/LCD/build #./lcd
Segmentation fault (`core 'generated)
root#ubuntu: /media/E80C-30D5/LCD/build #
Looking at dmesg I find this.
[3176.691837] lcd [3867] general
protection ip: 400cb4 sp: 7fff887ad290 error: 0 in lcd [+2000 400 000]root#ubuntu: / media/E80C-30D5/LCD/build #
I put the dmesg log of ttyS*
root # ubuntu: / media/E80C-30D5/LCD/build # dmesg | grep ttyS
[2.335717] serial8250: ttyS0 at I / O 0x3f8 (irq = 4) is a 16550A
[2.335817] serial8250: ttyS1 at I / O 0x2f8 (irq = 3) is a 16550A
[2.336100] 00:0 b: ttyS1 at I / O 0x2f8 (irq = 3) is a 16550A
[2.336207] 00:0 c: ttyS0 at I / O 0x3f8 (irq = 4) is a 16550A
root # ubuntu: / media/E80C-30D5/LCD/build #
Do not get it to run, you can help me please?
The code you're trying to run will not run in a "modern" operating system. Linux and versions of Windows after 16-bit will not let you perform operations that directly access ports or memory. Access to memory goes through a memory manager so the addresses you're specifying are not really the ones you end up accessing; and ports are accessed only by device drivers that are part of the operating system's kernel.
I'm not very sure, but if your main purpose is just to output some bytes via the serial port, then most of your code is not necessary, as you can simply write to a file that wraps the device driver to the port. There's a little more detail on this in this article.
If you really need to do bit-twiddling with the serial port chips, you can find some more information in the bottom line of this serial port mini-howto. Be warned that writing your own device driver is considered advanced.
EDIT: I just noticed your question mentions the parallel port but the port number in your code (3F8) is that for one of the serial ports. Hint: If the plug you're connecting to is a 9 pin port, then it's definitely a serial port. If it's a 25 pin port and female (holes, not pins) then it's probably a parallel port, if male it's probably a serial port. Or you could measure voltages: Serial port signals go up to +/- 9V or so, while the parallel port signals are from 0 to 5V.
I agree with others that you should write to the appropriate device file rather than perform I/O directly, if possible.
However, for the sake of completeness:
ioperm(PORTADDRESS,1,1)
should be
ioperm(PORTADDRESS,4,1)
Also, use parentheses to avoid bugs that results from incorrect macro expansion, like this:
#define PORTADDRESS (0x3f8)
#define DATA (PORTADDRESS+0)
#define STATUS (PORTADDRESS+1)
#define CONTROL (PORTADDRESS+2)
Instead of writing to an address outside your address space (which would make it PC-only if it would work), just write to a file (/dev/lp0, or wherever your parport is) instead.
Your LCD seems to talk serial, so why not use the serial port instead? Then your program would write to /dev/ttyS0 or something similar.
Related
I would like to send data from a C program into a Python program that will visualize this data. Development environment is a Linux (Ubuntu 18.04LTS) computer. To be clearer, both of the programs are running on the same computer.
I am using termios for opening the serial port in C program, and pySerial in the Python side. As for the serial port, I am using "ttyS0". The problem is that, when I send "Hello" from C program to the Python program and print it on the terminal what I see is space character, basically I am gettin this " ".
My question is, can I use the "ttyS0" serial port (I guess that is a virtual port) for this purpose?
Here is the C code:
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>
// Termios init functions are not posted because the configuration
// is correct and proved that they are working.
int main()
{
char *portname = "/dev/ttyS0";
int fd;
int wlen;
unsigned char writeBuffer[] = "Hello!";
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
do{
wlen = write(fd, writeBuffer, sizeof(writeBuffer));
printf("Sent data is: \"%s\"\n", writeBuffer);
delay(500);
} while(1);
}
The Python code:
import serial
from time import sleep
port = "/dev/ttyS0"
ser = serial.Serial(port, 115200, timeout=0.5)
while True:
data = ser.readline()
print(str(data.decode('utf-8')))
ser.close()
ttyS0 is your computer's serial port -- there's nothing "virtual" about it. Writing to this device will attempt to transmit data out of the computer using that port, and reading from the device will attempt to receive data from an external device connected to the port. There is no way for two programs on the same computer to usefully communicate using a serial port.
What I think you're looking for here is either a pipe, a socket pair, or a pty. Which one is most appropriate will depend on your specific requirements.
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.
I am trying to do SPI transfer in a raspberry pi. Raspberry pi comes with an SPI interface which send and recieves the data through it GPIO(General purpose input output pins). The spi driver information is here. I am doing loopback (connect MOSI and MISO pins). I had describe in my code what data I am sending, This data I will recieve due to loopback. I want a calculation on the recieved data. These data are stored in the form of array. After the calculation I need to print the results with proper sign, but I am not getting it.Here is my complete code.
/************************All header should come here************************************************************************ ********************************/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
/***************************All declaration should come here***************************************************************************************************/
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static const char *device = "/dev/spidev0.0";//selecting spi device in the raspberry pi
static uint8_t mode;//mode of spi transfer
static uint8_t bits =8;//no. of bits to be transfer, Pi supports 8 bit transfer
static uint32_t speed = 32000000;//spi clock speed,32 MHz is the maximum supported clock frequency
static uint16_t delay;
/*****************************Function definition should come here**********************************************************************************************/
/*function for transfer*/
static void transfer(int fd)//declaring a function for the transfer, this should be call in main program for transfer
{
int ret;// a return variable
uint8_t tx[]={4,5,6,5,4,3,5,4};// Array initialization
uint8_t rx[ARRAY_SIZE(tx)]={0,};//recieving array should be same as transferred array
struct spi_ioc_transfer tr= { // standard structure for spi driver usage
.tx_buf=(unsigned long)tx,//transmitting buffer
.rx_buf= (unsigned long)rx,//recieving buffer
.len = ARRAY_SIZE(tx),//length of trasnmitting buffer
.delay_usecs=delay,
.speed_hz = speed,
.bits_per_word= bits,
};
ret = ioctl (fd, SPI_IOC_MESSAGE(1), &tr);//comm. is done by ioctl command, This initializes the transfer
for (ret=0;ret< ARRAY_SIZE(tx);ret++){//recieving the data in rx buffer and rx array size is same as tx array size
if (!(ret%4))//meant for printing process
puts("");
printf("%d\t %X\n",ret, rx[ret]);//formatting
}//herer return is used as an index for the recieving array
printf("\n");
float x=((rx[1]+rx[3])-(rx[0]+rx[2]))/(rx[0]+rx[1]+rx[2]+rx[3]);
//x[1]=((rx[5]+rx[7])-(rx[4])+rx[5])/(rx[4]+rx[5]+rx[6]+rx[7]);
printf("%f\n",x);
}//end of function for the transfer
/************************Main Program****************************************************************************************************************************/
int main(int argc, char *argv[]){// start of main
int ret=0;//initializing return
int fd;// a file handle to handle the device as a file
fd=open (device,O_RDWR);//fd handles this device with read and write permission
ret=ioctl(fd, SPI_IOC_WR_MODE,&mode);
ret=ioctl(fd, SPI_IOC_RD_MODE,&mode);
ret=ioctl(fd, SPI_IOC_WR_BITS_PER_WORD,&bits);
ret=ioctl(fd, SPI_IOC_RD_BITS_PER_WORD,&bits);
ret=ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ,&speed);
ret=ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ,&speed);
transfer(fd);//transfer of data begins
close(fd);//close the file handle, it has opened earlier
return ret;
}
I Just need my output with proper sign after calculation on the data.
Do you honestly think that how the data came into printf() matters? It really doesn't, printf() has no idea that you're using SPI, of course.
If all you want is the plus/minus to appear (instead of just the minus for negative values), reading the manual page for printf() tells us:
+
A sign (+ or -) should always be placed before a number produced by a signed conversion. By default a sign is used only for negative numbers. A + overrides a space if both are used.
So, you should use:
printf("%+d\t%+d\n", x[0], x[1]);
I want to remote control sockets in my room manual without an extra library on my raspberry pi. I want to use the UART interface in C. The socket has 433 Mhz receiver and I use a 433 Mhz transmitter. In other librarys you type something like this: send 11111 1 1. (socket code, socket number, condition). But how to format this command in C with the write() function? The 10 is for number of characters. I use this code below. I tested the output via minicom, that works fine. But how the receiver now knows that it was adressed?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
int main(int argc, char ** argv) {
int fd;
// Open the Port. We want read/write, no "controlling tty" status, and open i$
fd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyAMA0 - ");
return(-1);
}
// Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
fcntl(fd, F_SETFL, 0);
// Write to the port
int n = write(fd,"11111 1 1",10);
if (n < 0) {
perror("Write failed - ");
return -1;
}
// Don't forget to clean up
close(fd);
return 0;
}
Do I get it right: you send a command via UART to transmit a message via radio trasmitter. Sniffing the UART output proves your code OK in the sense that TX line sends what you want it to send in the software, and the actual question is "how the rx module gets that message/how to make the rx module get it?"
If so, the main question is what kind of radio TX/RX or TRXs do you actually use (I mean chip/module codes, like CC1120, NRF2401 etc.)? There are plenty of 433MHz radiomodules available, I suppose consulting their datasheet first or at least posting the part number here is the right way to go.
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);
}