what is the purpose of direction in GPIO? - gpio

I've been looking at some node.js gpio libraries, and though I really like onoff, I don't want to be reliant on an installed python version (and it fails on my laptop because I've got python 3.3.2), so I'm looking at writing my own gpio library.
The basic idea of GPIO seems to simply be reading and writing to the specific GPIO file, and I'm guessing the operating system is looking for changes, or can make changes to that file.
All the libraries I see have a 'direction', but I'm thinking this seems a bit of overkill to me. If I am reading a value, my direction is 'out', if I'm writing to a file, my direction is 'in'. Is there some other reason that these are separated out in most of the libraries?
example from pi-gpio, which is a very simple library
https://github.com/rakeshpai/pi-gpio/blob/master/pi-gpio.js
gpio.open(16, "output", function(err) { // Open pin 16 for output
gpio.write(16, 1, function() { // Set pin 16 high (1)
gpio.close(16); // Close pin 16
});
});
and the open method in the library is
open: function(pinNumber, direction, callback) {
pinNumber = sanitizePinNumber(pinNumber);
if(!callback && typeof direction === "function") {
callback = direction;
direction = "out";
}
direction = sanitizeDirection(direction);
exec(gpioAdmin + " export " + pinMapping[pinNumber], handleExecResponse("open", pinNumber, function(err) {
if(err) return (callback || noop)(err);
gpio.setDirection(pinNumber, direction, callback);
}));
},

If you dig down through all the layers of abstraction, you'll see that many microprocessor / SoC devices expose GPIO through (at least) two hardware registers:
Data register
Direction register
The data register is of course what you read/write to get a value from an input pin, or change the value of an output pin.
The direction register controls whether a pin is an input or an output (or both). This affects the internal buffering / output driver circuitry associated with that pin.
For example, a GPIO pin configured for "input" (or reading) will be in a high-impedance (high-Z) state, so it presents little to no load to the connected circuitry. On the other hand, an output pin will usually be pulled to either Vcc or GND.
What you're seeing is this necessary direction register being abstracted all the way up to the Javascript level, where it seemingly makes no sense. As the electrical engineers, however. It is necessary.

Related

Dallas 1 Wire Protocol with Yocto/Raspberry Pi 3

I have been trying to get a custom Yocto build off the ground for some time now. The goal is to connect a DS18b20 thermometer to the GPIO pins and test that it is indeed working. I have gotten as far as building out the base image and adding on all of the software packages I needed to it. The problem presents itself when I try to connect and detect the thermometer with my custom firmware image. It boots fine, networking works, wifi works, have not tried BT yet as I don't need it, but the GPIO pins are the ones that are not proving to be of help.
I am using a 4.9.x Linux Kernel on it. Is it recommended I downgrade to a 4.4.x Linux Kernel? I've pretty much run out of ideas at this point, just need some help to figure it out. f
This device is supported by the kernel, no need to mess with searching or writing your own w1 driver.You will need to ensure the CONFIG_W1_SLAVE_THERM, CONFIG_W1_MASTER_GPIO and CONFIG_W1 are set in you kernel config (consult the Yocto kernel documentation for setting this one-time or in a way that will persist over several builds).
This usually leaves the only remaining gap being which GPIO pin is used for w1. Without knowing which device you are using I can only provide some pointers. The connection is defined via a platform data. This can be defined in the device tree, for example with a c.h.i.p.
onewire {
compatible = "w1-gpio";
gpios = <&pio 3 2 GPIO_ACTIVE_HIGH>; /* PD2 */
pinctrl-names = "default";
pinctrl-0 = <&chip_w1_pin>;
};
Where PD2 == LCD-D2 on the header.
Alternatively it can be defined in the mach-* in the kernel, for example
static struct w1_gpio_platform_data w1_gpio_platform_data = {
.pin = GPIO_ONE_WIRE,
.is_open_drain = 0,
};
static struct platform_device raumfeld_w1_gpio_device = {
.name = "w1-gpio",
.dev = {
.platform_data = &w1_gpio_platform_data
}
};
A google search of 'w1-gpio map gpio' should return more and better details. If you can use the device tree approach, that is what they are made for. Just know that the kernel code doesn't cycle through the GPIO pins looking for connected w1 devices, this mapping has to be set.
If the device is attached and working you will be able to get its value by doing 'cat /sys/bus/w1/devices/28*/w1_slave'. If you are using python you can use https://github.com/timofurrer/w1thermsensor to make reading the temperature easy. Or use equivalent libraries for your preferred language.

UART Interrupts disabling I/O on Sam3X8E/ Arduino Due

I am starting to use an Arduino Due for some project work which requires a UART and am confused by what looks like an interaction between UART interrupts and I/O.
My first piece of code was a small routine to set up the UART, send out data continuously by loading the transmit buffer upon receipt of a TXBE interrupt. I had the UART output hooked up to an oscilloscope and had set another I/O pin as a general purpose output which would flip state and therefore be used to trigger the scope when the transmit buffer was reloaded. Problem was that I was seeing UART data and it looked good, but the I/O wasn't flipping. At this point my loop() routine was empty so I set up another output port and in loop() just toggled its state as a sanity check. Still no output except for the UART.
Here's the code that I ended up with:
uint32_t tempo; // 32-bit temporary variable
boolean flag = true;
void UART_Handler(void) {
REG_UART_THR = 0x6DL; // load data into the transmit buffer
if (flag) {
REG_PIOD_SODR = 0x02L; // drive PD1 high
flag = false;
} else {
REG_PIOD_CODR = 0x02L; // drive PD1 low
flag = true;
}
}
void setup() {
// set up the UART I/O
REG_PIOA_IDR = 0x0300L; // disable interrupts on PA8 and PA9
tempo = REG_PIOA_ABSR; // get the current settings of the AB select register
REG_PIOA_ABSR = tempo & 0xFFFFFCFF; // set PA8 and PA9 to peripheral A control
REG_PIOA_PDR = 0x0300L; // disable parallel I/O for PA8 and PA9
NVIC_EnableIRQ(UART_IRQn); // enable UART interrupts in NVIC
// now set up the UART
tempo = REG_PMC_PCSR0; // get the current settings of the peripheral clock register 0
REG_PMC_PCER0 = tempo | 0x0100L; // enable the UART clocks
REG_UART_CR = 0x0CL; // reset UART receiver and transmitter
REG_UART_MR = 0x0800L; // set to normal outputs with no parity
REG_UART_BRGR = 0x89L; // baud rate set to 38400
REG_UART_IDR = 0x1FBL; // disable all UART interrupts
REG_UART_IER = 0x0800L; // enable TXBUFE interrupt
REG_UART_CR = 0x50L; // enable UART receiver and transmitter
// set up the debug outputs
REG_PIOD_IDR = 0x03L; // disable interrupts on PD0 and PD1
REG_PIOD_PER = 0x03L; // enable parallel I/O for PD0 & PD1
REG_PIOD_OER = 0x03L; // set PD0 & PD1 output enabled
REG_PIOD_CODR = 0x03L; // drive PD0 & PD1 low
}
void loop() // run over and over
{
REG_PIOD_SODR = 0x01L; // drive PD0 high
delay(1);
REG_PIOD_CODR = 0x01L; // drive PD0 low
delay(1);
}
the scope output can be viewed at http://www.iwanczuk.com/temp/scope1.png (don't have enough reputation here to post images!).
After staring at things for while and getting no insight I disabled the TXBUFE interrupts by commenting out the line REG_UART_IER = 0x0800L; // enable TXBUFE interrupt and the toggling of PortD1 was then visible but obviously no UART output (see http://www.iwanczuk.com/temp/scope2.png). It seems that the two are mutually exclusive which would be just silly if it were true. I am sure I'm missing something but I can't see or find what it is.
I have read the SAM3X8E data sheet to see if there's anything obvious I'm missing and if there is I can't see it. I've also done what I think are relevant web searches with no luck in finding a solution. I have also tried using general purpose outputs for the two outputs on port A and port D and have tried this on two Arduino Due boards with similar results on both.
Anyone have any ideas what I might be doing wrong? Thanks in advance.
Well, I have got to the bottom of this problem. Not sure it's the best answer but it's a solution. The long and short of it is to avoid TXBE interrupts. If I use TXEMPTY interrupts instead it works fine.
A line on page 168 of the Atmel data sheet says (sic) "A interrupt can enter pending state even it is disabled" so I wondered if the problem with TXBE was because I was not clearing the pending interrupt before or even inside the ISR so I added NVIC_ClearPendingIRQ(UART_IRQn); at the start of the ISR and also just before I enabled the TXBE interrupt but the (mis)behaviour didn't change.
The operation of TXEMPTY is still a little odd (to me) because it appears that the interrupt is generated by the transmit shift register just being empty, not when it goes empty. If you enable interrupts without having loaded the transmit buffer you will immediately get an interrupt. Some may like this "self=priming' behaviour, but it doesn't do it for me. I am writing my sending routine such that the TXEMPTY interrupt is not enabled until the transmitter has been loaded with the first byte to be sent.
Based on this post on the Arduino Forum: http://forum.arduino.cc/index.php?topic=186388.0 I presume that the USARTs have a similar issue.
Hopefully this will help others.
I just realised what could be the real error at the source of my problem. The UART interrupt register descriptions talk about the TXBUFE bit in the context of transmit buffer empty and so my assumption was that this is the bit that tells me when I can put another byte into the transmit holding register. However the UART Status Register description say that the TXBUFE bit is "the buffer full signal from the transmitter PDC channel". The latter puts a whole different slant on what this bit does. According to the UART Status Register description the bit I need to be looking at is the TXRDY bit!

How can I digitalRead a pin and convert data to String on Arduino?

I'm doing a communication system with 2 Arduinos Leonardo. To transmit I had to convert a String in bits and send them through a PWM pin. The question is, how can I do the receiver?
My idea is to receive data in a digital pin, so I can convert LOW/HIGH to '0' and '1', put 8 bits in a string, convert to char and then I have my final String.
Some info:
- I'm using PWM because I want to implement FSK modulation, sending bit by bit;-
- I have some hardware to get communication system working;
- My physical channel for communication is Serial (via Arduino pins);
- In the receiver hardware will provide me TTL signals, so I will have 0V/5V. That's why I think digitalRead() should work;
- Data is sent via PWM and received in two level signals;
- I'll have to do some protocol to send/receive data, but still don't know how...
This is the code I wrote:
void setup() {
Serial.begin(9600);
while (!Serial) {;}
}
void loop() {
char bitPosition = 0;
String inMessage = 0;
while (Serial.available() > 0) {
char outChar;
boolean digValue = digitalRead(inPin);
for(bitPosition = 7; bitPosition >= 0; ){
if(digValue == LOW){
bitWrite(outChar, bitPosition, 0);
}
if(digValue == HIGH){
bitWrite(outChar, bitPosition, 1);
}
bitPosition--;
}
inMessage.concat(outChar);
if(inMessage != 0){
Serial.println("Received: " + inMessage);
}
}
}
I want this code to transform HIGH/LOW states from digitalRead in a string of characters. 0/1 -> char (outChar) -> String (inMessage). I don't know if i'm not thinking right. Suggestions?
Should I have to do something about baudrate to receive/transmit data? How?
Any help/suggestion would be appreciated.
Look at how SoftwareSerial is implemented in Arduino for a clue as to how to get this done.
http://arduino.cc/en/Reference/SoftwareSerial
"The SoftwareSerial library has been developed to allow serial communication on other digital pins of the Arduino, using software to replicate the functionality (hence the name "SoftwareSerial")."
Well, your problem if far more complicated that you believe. I have read your similar (identical?) question posted on EE.SE.
It seams that you haven't catch a fundamental thing about your issue.
It is not a software problem. If I summarize your issue, globally.
You want to send data from arduino A to arduino B.
You plan to generate a FSK signal using a PWM pin of arduino A.
first comment: How ? Look-up table of a sine wave where the pointer moves according to the phase modulation? This seems easy. So let's believe this it the way you choose.
(here you say it is a logic signal, but on EE.SE you say it's a wireless signal)
Now you have a signal at XX kHz (we don't know the XX value. But accordint to the Xtal speed of your Arduino, I can't be much greater than ~500Khz)
On arduino B, you have to solve the problem of clock recovery because on arduino B you don't have access to the clock of arduino A. This means that you can't compare the signal you are getting with a reference clock. When you analyse the received signal you get a certain phase relative to your local clock. But because you cannot know the reference phase of ardunio A, you cannot say if the receive bit is -90° or +90°. Thus you can't assign a 0 or 1 to the received signal.
This is not a trivial problem. According to your answer to the question and comments here or on EE.SE, you are trying to solve implementation problem of an algorithm that is probably not working. Your should first try to find a suited algorithm that you may simulate using MATLAB (or the free OCTAVE), make sure it is working, and next try to implement it on embedded hardware.
You receive a lot of answer on EE.SE about what do you want to do. It's because it makes no sens to solve an issue about implementing something that looks false to an expert.
Thus, if you want meaningful answers. Please spend more time explaining us what and how, conceptually, you plan to solve your problem.
Add information about how your think your FSK works. How do you plan to use PWM to do FSK, this in not trivial. And how you plan, conceptually to detect that a received symbol is a 1 or a 0.
As it is, my answer is : Event if we can solve you copy bit issue, it won't solve your problem.

Linux device driver handling multiple interrupt sources/vectors

I am writing a device driver to handle interrupts for a PCIe card, which currently works for any interrupt vector raised on the IRQ line.
But it has a few types that can be raised, flagged by the Vector register. So now I need to read the vector information and be a bit cleverer...
So, do I :-
1/ Have separate dev nodes /dev/int1, /dev/int2, etc for each interrupt type, and just doc that int1 is for vector type A etc?
1.1/ As each file/char-devices will have its own minor number, when opened I'll know which is which. i think.
1.2/ ldd3 seems to demo this method.
2/ Have one node /dev/int (as I do now) and have multiple processes hanging off the same read method? sounds better?!
2.1/ Then only wake the correct process up...?
2.2/ Do I use separate wait_queue_head_t wait_queues? Or different flag/test conditions?
In the read method:-
wait_event_interruptible(wait_queue, flag);
In the handler not real code! :-
int vector = read_vector();
if vector = A then
wake_up_interruptible(wait_queue, flag)
return IRQ_HANDLED;
else
return IRQ_NONE/IRQ_RETVAL?
EDIT: notes from peoples comments :-
1) my user-space code mmap's all of the PCIe firmware registers
2) User-space code has a few threads, each perform a blocking read on the device driver device nodes, which then returns data from the firmware when an interrupt occurs. I need the correct thread woken up depending on the interrupt type.
I am not sure I understand correctly what you mean with the Vector register (a pointer to some documentation would help me precise for your case).
Anyway, any PCI device gets a unique interrupt number (given by the BIOS or some firmware on other architectures than x86). You just need to register this interrupt in your driver.
priv->name = DRV_NAME;
err = request_irq(pdev->irq, your_irqhandler, IRQF_SHARED, priv->name,
pdev);
if (err) {
dev_err(&pdev->dev, "cannot request IRQ\n");
goto err_out_unmap;
}
One other thing that I do not really understand is why you would export your interrupts as a dev node: interrupts are certainly something that need to remain in your driver/kernel code. But I guess here you want to export a device that is then accessed in userspace. I just find /dev/int no to be a good naming.
For your question about multiple dev nodes: if your different interrupt sources then provide access to different hardware resources (even if on the same PCI board) I would go for option 1), with a wait_queue for each device. Otherwise, I would go for option 2)
Since your interrupts are coming from the same physical device, if you chose option 1) or option 2), the interrupt line will have to be shared and you will have to read the vector in your interrupt handler to define which hardware resource raised the interrupt.
For option 1), it would be something like this:
static irqreturn_t pex_irqhandler(int irq, void *dev) {
struct pci_dev *pdev = dev;
int result;
result = pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &myirq);
if (result) {
int vector = read_vector();
if (vector == A) {
set_flagA(flag);
} else if (vector == B) {
set_flagB(flag);
}
wake_up_interruptible(wait_queue, flag);
return IRQ_HANDLED;
} else {
return IRQ_NONE;
}
For option 2, it would be similar, but you would have only one if clause (for the respective vector value) in every different interrupt handler that you would request for every node.
If you have different chanel you can read() from, then you should definitely use different minor number. Imagine you have a card whith four serial port, you would definitely want four /dev/ttySx.
But does your device fit whith this model ?
First, I assume you're not trying to get your code into the mainline kernel. If you are, expect a vigorous discussion about the best way to do this. If you're writing a simple interrupt handling driver for a card which is mostly driven by mmap from user-space, there are a lot of ways to solve this problem.
If you use multiple device nodes (option 1), you can also implement poll so that a single application can open multiple device nodes and wait for a selection of interrupts. The minor number will be sufficient to tell them apart. If you have a wake queue for each vector, you can wake only the relevant listeners. You'll need to latch the vector after a successful poll to be sure that the read succeeds.
If you use a single device node (option 2), you'll need to add some extra magic so that the threads can register their interest in particular interrupt vectors. You could do this with an ioctl, or have the threads write the interrupt vectors to the device. Each thread should open the device node to get its own file descriptor. You can then associate the list of requested vectors with each open file descriptor. As a bonus, you can let the application read the interrupt vector from the device, so it knows which one happened.
You'll need to think about how the interrupt gets cleared. The interrupt handler will need to remove the interrupt, then store the result so it can be passed to user-space. You might find a kfifo useful for this rather than a wait queue. If you have a fifo for each open file descriptor, you can distribute the interrupt notifications to each listening application.

polling file descriptor

for the embedded MIPS-based platform I'm implementing a small program to poll GPIO, i.e. I'm using chip vendor's user level GPIO library with basic functionality (open /dev/gpio, read, write pin etc.). The design is straightforward:
int gpio_fd;
fd_set rfds;
gpio_fd = gpio_open(...);
while (1) {
FD_ZERO(&rfds);
FD_SET(gpio_fd, &rfds);
if (select(gpio_fd + 1, &rfds, NULL, NULL, NULL) > 0) {
if (FD_ISSET(gpio_fd, &rfds)) {
/* read pins and similar */
}
}
}
But I'm facing a serious problem - this application when ran with '&' at the end, i.e. put it in background, consumes 99% CPU, this is obviously because of tight loop, but I observed the similar approach in many networking code and it worked fine.
Am I missing something, can it be a defect of the gpio library ?
Actually, just a single "while(1) ; " does the same effect. Can it be the "natural" behavior of the kernel?
Thanks.
The select call should block until the file descriptor is readable.
What may be happening is that the device driver does not support the select call, and so it exits immediately rather than blocking.
Another possibility is that the call to gpio_open does not actually give you a real Unix file descriptor. If that were open("/dev/gpio", O_RDWR) or something like that I'd have a lot more faith in it.

Resources