Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Creating a pwm signal by hand

Fri Jun 13, 2014 11:04 am

Sorry guys, i've searched here and there but could not find a solution..
Starting poing: i want to CREATE a ir signal (output through a ir emitter linked to a GPIO), that have to be PWM at something between 33 and 38 kHz.
More than that, the signal will have to switch level in at least 400us.

I've seen that PWM is widely supported on the PI.
Software via dma or hardware, haven't understood that much..
Wiringpi seems to have a quite low limit for the pwm frequence (much lower than what i'm looking for), and it seems to me that it has to use GPIO 18 (that i have to use with lirc even if i change the configuration for input gpio.. dunno why..)

So, i'm not asking a complete code, but something like "use c because python has garbage collection" (ok, i'll use c), "use this library instead of this because this is faster", and so on..
I mean, a start point :)

Thanks a lot..

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 11:40 am

Are you sure you need to generate the 38KHz carrier? Usually the IR chip will generate the carrier modulated with the signal you add (that's certainly how the receivers work).

Anyhow, to generate the waveform you can use pigpio.

http://abyz.co.uk/rpi/pigpio/index.html

A morse code Python example http://abyz.co.uk/rpi/pigpio/code/morse_code_py.zip

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 12:19 pm

joan wrote:Are you sure you need to generate the 38KHz carrier? Usually the IR chip will generate the carrier modulated with the signal you add (that's certainly how the receivers work).
Receivers have a band filter.. transmitter often (and this is my case) are only a IR led, a transistor and a couple of resistors :)
But that's good for my, i can (i hope :)) create ir signals for my ac and for my tv (different carrier frequence)
Anyhow, to generate the waveform you can use pigpio.

http://abyz.co.uk/rpi/pigpio/index.html

A morse code Python example http://abyz.co.uk/rpi/pigpio/code/morse_code_py.zip
will this manage pwm frequence around 35kHz and switching speed around 300us? with python?
my python scripts can't even speak about us in time.time() function!
am i missing something?

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 12:29 pm

I don't understand how you will modulate the signal.

It can certainly generate a 35 kHz carrier (assume you need 14 micros on/ 14 micros off). The resolution is 1 microsecond. See http://www.raspberrypi.org/forums/viewt ... 19#p563619 for a 256kHz square wave.

Twinkletoes
Posts: 210
Joined: Fri May 25, 2012 9:44 pm

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 12:31 pm

Look at how https://github.com/richardghirst/PiBits ... rvoBlaster does it.

From the readme:
The driver works by setting up a linked list of DMA control blocks with the
last one linked back to the first, so once initialised the DMA controller
cycles round continuously and the driver does not need to get involved except
when a pulse width needs to be changed. For a given period there are two DMA
control blocks; the first transfers a single word to the GPIO 'clear output'
register, while the second transfers some number of words to the PWM FIFO to
generate the required pulse width time.
The DMA blocks get transferred without using the ARM, so you can set up bit streams that run once, or loop back to the beginning and repeat. You can get very fast bitrates this way.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 2:58 pm

Thank you guys, i'll give it a try :)
To check it i'll also try to get a working piscope :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 3:09 pm

pattagghiu wrote:Thank you guys, i'll give it a try :)
To check it i'll also try to get a working piscope :)
I'd use one of the pre-built images if you can. Gtk seems to use a ridiculous amount of space (a lot of space seems to be used by unneeded debug symbols).

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 3:15 pm

joan wrote:
pattagghiu wrote:Thank you guys, i'll give it a try :)
To check it i'll also try to get a working piscope :)
I'd use one of the pre-built images if you can. Gtk seems to use a ridiculous amount of space (a lot of space seems to be used by unneeded debug symbols).
ehm..
i think my problem is bigger...
first of all, i dunno if i'm HARD or SOFT (float) :)
but more than this.. is there any possibility to see the piscope output on windows? :D

Hey, this is beginners section, i'm noob by definition :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 13, 2014 3:21 pm

Re piscope.

All the recent Pi distributions are hard float.

I had no luck compiling the program on Windows. I abandoned the attempt.

I know one person has it working on a Mac. I use the pre-built image on my 64-bit Linux laptop.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Sun Jun 15, 2014 2:20 pm

joan wrote:I don't understand how you will modulate the signal.

It can certainly generate a 35 kHz carrier (assume you need 14 micros on/ 14 micros off). The resolution is 1 microsecond. See http://www.raspberrypi.org/forums/viewt ... 19#p563619 for a 256kHz square wave.
this is quite clear.
The only (lol, ok, one of a thousand..) doubt i have is if i can trust in python time.sleep for 400us sleep..

for the rest, i shouls use the wave for "pulse" periods and only sleep for space periods..
i think, at least :)

will this work with correct time?

Code: Select all

pi.wave_send_repeat(wid)
time.sleep(0.0004)
pi.wave_tx_stop()

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Sun Jun 15, 2014 2:45 pm

pattagghiu wrote: ...
The only (lol, ok, one of a thousand..) doubt i have is if i can trust in python time.sleep for 400us sleep..

for the rest, i shouls use the wave for "pulse" periods and only sleep for space periods..
i think, at least :)

will this work with correct time?

Code: Select all

pi.wave_send_repeat(wid)
time.sleep(0.0004)
pi.wave_tx_stop()
No, time.sleep(0.0004) won't work as you want. As you say neither Python (nor C) can guarantee a delay. All you can be sure of is that the delay will be at least as long as what you specified.

I still don't understand how the signal is formed. You have a 38kHz carrier wave. How are 1s and 0s represented?

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Sun Jun 15, 2014 3:51 pm

joan wrote:
pattagghiu wrote: ...
The only (lol, ok, one of a thousand..) doubt i have is if i can trust in python time.sleep for 400us sleep..

for the rest, i shouls use the wave for "pulse" periods and only sleep for space periods..
i think, at least :)

will this work with correct time?

Code: Select all

pi.wave_send_repeat(wid)
time.sleep(0.0004)
pi.wave_tx_stop()
No, time.sleep(0.0004) won't work as you want. As you say neither Python (nor C) can guarantee a delay. All you can be sure of is that the delay will be at least as long as what you specified.

I still don't understand how the signal is formed. You have a 38kHz carrier wave. How are 1s and 0s represented?
In ir signal (as far as i have understood..) 1s and 0s are represented with "an high level and a low level". Depending on the duration of each level, it's a 1 or a 0
something like that

http://electronics.howstuffworks.com/re ... ntrol2.htm

To be received, "high level" must be modulated (thats' che square wave you showed me)

It seems to me that - having the modulated wave - what i have to do to create the output signal is.. manage delay!

For a "1" i'll have to output the modulated wave for a little time, and nothing for another time..
For a "0" i'll have to output the modulated wave for a little time, and nothing for another time..

It's all about delays..
So how can i achieve this?

As said before, i'm talking about times of 400us

Edit: i'd like to underline that in this case 401us and 399us are exactly the same. Reading output from a remote control (with lirc) i can read times i'd see from 350 to 450 us, so it doesn't need to be exact to one us.. what i fear is that time.sleep in python will be MUCH more wrong than 10 us..

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Sun Jun 15, 2014 4:37 pm

OK. I just had a look through http://www.hifi-remote.com/infrared/IR-PWM.shtml and it does seem to be a simple pulse width modulation. Carrier on / carrier off for varying periods to encode bits.

Have a look at the following code and see if you can follow what I'm trying to do. I guess you'll need something similar.

Code: Select all

#!/usr/bin/env python

import pigpio

class tx:

   """
   """

   def __init__(self, pi, gpio, carrier_hz):

      """
      Initialises an IR tx on a Pi's gpio with a carrier of
      carrier_hz.
      """

      self.pi = pi
      self.gpio = gpio
      self.carrier_hz = carrier_hz
      self.micros = 1000000 / carrier_hz
      self.on_mics = self.micros / 2
      self.off_mics = self.micros - self.on_mics

      self.wf = []
      self.wid = -1

      pi.set_mode(gpio, pigpio.OUTPUT)

   def clear_code(self):
      self.wf = []
      if self.wid >= 0:
         self.pi.wave_delete(self.wid)

   def send_code(self):
      pulses = self.pi.wave_add_generic(self.wf)
      print("waveform uses {} pulses".format(pulses))
      self.wid = self.pi.wave_create()
      if self.wid >= 0:
         self.pi.wave_send_once(self.wid)
         while self.pi.wave_tx_busy():
            pass

   def add_to_code(self, on, off):

      # add on cycles of carrier
      for x in range(on):
         self.wf.append(pigpio.pulse(1<<self.gpio, 0, self.on_mics))
         self.wf.append(pigpio.pulse(0, 1<<self.gpio, self.off_mics))

      # add off cycles of no carrier
      self.wf.append(pigpio.pulse(0, 0, off * self.micros))

if __name__ == "__main__":

   import time
   import pigpio
   import ir_tx

   pi = pigpio.pi()

   tx = ir_tx.tx(pi, 22, 38000)

   tx.clear_code()

   tx.add_to_code(23, 46) # 1
   tx.add_to_code(23, 46) # 1
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 46) # 1
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 46) # 1
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 46) # 1
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 46) # 1
   tx.add_to_code(23, 23) # 0
   tx.add_to_code(23, 23) # 0

   tx.send_code()
   tx.clear_code()

   pi.stop()
The above code used 658 pulses to generate the following waveforms.
ir_tx_1.png
ir_tx_1.png (41.47 KiB) Viewed 8679 times
ir_tx_2.png
ir_tx_2.png (40.66 KiB) Viewed 8679 times
ir_tx_3.png
ir_tx_3.png (40.34 KiB) Viewed 8679 times

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Sun Jun 15, 2014 5:02 pm

wow, if i've understood you are creating the wave with pulse and spaces inside.. that's great, much better than leaving spaces with sleep..
very nice, i'll try it :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Sun Jun 15, 2014 5:11 pm

pattagghiu wrote:wow, if i've understood you are creating the wave with pulse and spaces inside.. that's great, much better than leaving spaces with sleep..
very nice, i'll try it :)
Yes, that's right. A pulse doesn't have to switch any gpios on or off, it can just be a delay.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Tue Jun 17, 2014 12:47 pm

hey man, i think i've understood all of your script :) but i've a couple of question:
- i'll rewrite it thinking in "time" instead of "cycles", i think this should not be a problem, right (i.e.: off for 400us, not for 13 cycles..)? there will be some for and some while, but nothing strange.. this is going to be something about the program itself and not the wave, i assume..
- when you add the "space", i mean here

Code: Select all

# add off cycles of no carrier
self.wf.append(pigpio.pulse(0, 0, off * self.micros))
you are not passing any GPIO to be turned on or off, so this will work only if "before" this command the GPIO is already OFF. This should always work, thinking to my signal, but what if i force GPIO off even if it's already off? (just to be sure..)
I mean use this, instead

Code: Select all

# add off cycles of no carrier
self.wf.append(pigpio.pulse(0, 1<<self.gpio, off * self.micros))

Last but not least, and not regarding your fantastic script, a nooooooob question:
- as far as i've understood, to use pigpio in python i need the daemon running. To get it running by default at system startup, is this right?

Code: Select all

update-rc.d pigpiod defaults
I only googled, don't understand what i'm doing :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Tue Jun 17, 2014 1:39 pm

Using micros instead of cycles will be fine. I was guided by the link I posted where they defined the lead in, the pulses themselves, and the lead out by cycles of carrier on and carrier off. If I was doing this myself I would use cycles rather than micros as I can see the merit in using cycles.

There is no harm in explicitly turning the IR LED off at the start of the delay. I knew it was off because each carrier on cycle ends with the gpio being switched off. If you use micros it is safer to do as you suggest and explicitly switch the gpio off.

As far as setting up a service have a look at http://www.raspberrypi.org/forums/viewt ... 87#p516187 where danjperron shows how to set the daemon as a service.

It's not something I do as I'm forever tinkering making minor mods here and there to the software.


Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 9:37 am

since this topic is going to be abandoned, i'd like to make a "different" question :)
you showed me how to create a wave setting all levels and times BEFORE and then create it.
Is there the possibility to have the opposite function?
I mean, can i read a wave from a GPIO input and have it "written" to work on levels and timing?
something like
low for 10us
high for 50us
and so on..
In this way i can work on the waveform without all the timing problem of python..
Let's say, an offline oscilloscope :)

Thanks guru :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 9:53 am

If I understand you need to use something like http://abyz.co.uk/rpi/pigpio/code/ir_hasher_py.zip which reads the levels from an IR receiver and generates a hash over the level changes. Rather than generating a hash you could just print out the edge details.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 10:18 am

joan wrote:If I understand you need to use something like http://abyz.co.uk/rpi/pigpio/code/ir_hasher_py.zip which reads the levels from an IR receiver and generates a hash over the level changes. Rather than generating a hash you could just print out the edge details.
i haven't understood much, but it seems to me that it uses interrupts to find level switches.
This is the "easy way" and my fear is that python is not precise enough to write somewhere (Even in a list in memory, i mean) level switch timings when we are talking about a hundred of us or something like that..
But i'll try :)
i was only wondering if there is the "dma" way of managing this :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 10:29 am

pattagghiu wrote:
joan wrote:If I understand you need to use something like http://abyz.co.uk/rpi/pigpio/code/ir_hasher_py.zip which reads the levels from an IR receiver and generates a hash over the level changes. Rather than generating a hash you could just print out the edge details.
i haven't understood much, but it seems to me that it uses interrupts to find level switches.
This is the "easy way" and my fear is that python is not precise enough to write somewhere (Even in a list in memory, i mean) level switch timings when we are talking about a hundred of us or something like that..
But i'll try :)
i was only wondering if there is the "dma" way of managing this :)
On the input side pigpio uses DMA to sample the gpios 200000 times a second (default, can be sampled at 1000000 times per second). The samples are timestamped so by default you get level changes accurate to 5 microseconds. I don't think there is any means of getting better accuracy without writing a kernel module and dedicating the Pi to a single usage.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 10:48 am

joan wrote:On the input side pigpio uses DMA to sample the gpios 200000 times a second (default, can be sampled at 1000000 times per second). The samples are timestamped so by default you get level changes accurate to 5 microseconds.
so using interrupts and writing the output of time.time() (python speaking) as callback should be enough?
seems easy :)

User avatar
joan
Posts: 15940
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 11:01 am

pattagghiu wrote:
joan wrote:On the input side pigpio uses DMA to sample the gpios 200000 times a second (default, can be sampled at 1000000 times per second). The samples are timestamped so by default you get level changes accurate to 5 microseconds.
so using interrupts and writing the output of time.time() (python speaking) as callback should be enough?
seems easy :)
Using Python pigpio callbacks and using the (tick) time-stamp will be enough. The Python pigpio callbacks are fed the sample stream.

You can't use system interrupts as 1) you don't know when they occurred, 2) you will miss level changes. You can't use time.time() as there is no relationship between that time and when the "event" you are time-stamping happened.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Creating a pwm signal by hand

Fri Jun 20, 2014 11:22 am

joan wrote:Using Python pigpio callbacks and using the (tick) time-stamp will be enough. The Python pigpio callbacks are fed the sample stream.
i need some study, but this is clear.
As always, thank you :)

Return to “Beginners”