gkaindl / ambi-tv

a flexible ambilight clone for embedded linux
296 stars 85 forks source link

UART sink #38

Closed stozze closed 8 months ago

stozze commented 10 years ago

Hi,

I wrote this sink that outputs the data over uart. I then used a microcontroller to parse the data and output the result to WS2811 led strips. Maybe somebody else finds it useful too.

I've only tested this with an USB <-> UART dongle but internal uart module on the RPI should work fine too.

Thanks for creating ambi-tv, awesome work!

Phil1988 commented 10 years ago

Maybe it is useful for me :-) Can I use this to connect the PI with an Arduino which controlls the WS2811 (in my case WS2812B) LEDs? I have no USB<->UART dongle will it work direclty from raspberry to arduino?

Can you give me an instruction how to do this? Thanks!

Phil1988 commented 10 years ago

Sadly this version give me an error:

pi@raspberrypi ~/ambi-tv-master $ sudo bin/ambi-tv --button-gpio 3


registration: registered component 'v4l2-video' (class v4l2-grab-source). device name: /dev/video0 buffers: 4 crop-top: 1 crop-right: 4 crop-bottom: 1 crop-left: 4 auto-crop luma threshold: 8 registration: registered component 'timer-30fps' (class timer-source). millis: 33 registration: registered component 'led-frame' (class lpd8806-spidev-sink). device name: /dev/spidev0.0 spi hz: 2500000 number of leds: 98 blending frames: 3 led insets (tblr): -0.8%, -3.0%, -9.0%, -9.0% gamma (rgb): 1.55, 1.60, 1.50 uart-sink: unrecognized option '--spi-device' uart-sink: unrecognized option '--spi-speed-hz' uart: extraneous argument: '/dev/ttyUSB0'. parse-config: /etc/ambi-tv.conf, line 57: failed to instantiate configuration block 'uart-sink'. main: failed to parse configuration file, aborting...

checked if src/components/ is containing "uart-sink.c" and it is.. (aswell as the other files..) any ideas?

Phil1988 commented 10 years ago

There is a mistake in the sample.conf. "spi-device" and "spi-speed-hz" doesnt exist in uart-sink.c it must be "uart-device" and "uart-baudrate"

yours looks like: uart-sink { name led-frame-uart spi-device /dev/ttyUSB0 spi-speed-hz 460800 leds-top 34-63 # left-to-right leds-bottom 13-0,4X,97-84 # left-to-right leds-left 33-14 # top-to-bottom leds-right 64-83 # top-to-bottom led-inset-top -0.75 led-inset-bottom -3.0 led-inset-left -9.0 led-inset-right -9.0 blended-frames 3 gamma-red 1.55 gamma-green 1.6 gamma-blue 1.5 }

but ist must be:

uart-sink { name led-frame-uart uart-device /dev/ttyUSB0 uart-baudrate 460800 leds-top 34-63 # left-to-right leds-bottom 13-0,4X,97-84 # left-to-right leds-left 33-14 # top-to-bottom leds-right 64-83 # top-to-bottom led-inset-top -0.75 led-inset-bottom -3.0 led-inset-left -9.0 led-inset-right -9.0 blended-frames 3 gamma-red 1.55 gamma-green 1.6 gamma-blue 1.5 }

I started some testing with the integrated UART of the Raspberry. On minicon I got some success and send data from Raspberry to Arduino. Sadly I couldnt get above 115200 baud - is this necessary? The problem is that the ambi-tv doesnt send anything if I start with

uart-sink { name led-frame-uart uart-device /dev/ttyAMA0 uart-baudrate 115200 ... }

and enter sudo bin/ambi-tv --button-gpio 3 in putty... any ideas?

stozze commented 10 years ago

You are right, I forgot to change spi-device to uart-device, and spi-speed-hz to uart-baudrate in sample.conf. Fixed those now.

When you said you didn't get any output, did you change the sink for the programs in the sample.conf file to led-frame-uart instead of led-frame?

115200 might be fast enough for a few leds, but higher baudrates will be needed if you want decent update rates. I used two buffers in my microcontroller, one is used for receiving data and the other one is used to refresh the ws2811 leds. After the receive buffer was filled with new data, the two buffers are swapped.

Going above 115200 was also one of the reasons to using the usb uart dongle instead of internal uart module in the PI. Not sure if it is possible to get stable baudrates above 115200 on the PI.

Phil1988 commented 10 years ago

Hey stozze! I'm glad you responsed!

Well I have the config like you updated 5 hours before - but with an uart-baudrate of 115200 - the rest ist exactly the same. (like here https://github.com/stozze/ambi-tv/blob/356646e5ab433b6df489f4ee5907c86dea353c5c/sample.conf )

Do I have to "activate" the led-frame-uart and deactivate the led-frame somewhere? As far as I understant this config - both sinks are running simultaneously because the lpd8806-spidev-sink and the uart-sink existing in the sample.conf

I testet to connect the PI to an Arduino (just PI's TxD to Arduinos RxD) and succeed to send chars over minicom with an baud rate of 115200. (showed them in Serial-Monitor)

I dont know in which format the received data will be or how I can handle them.

I already bought a USB<-> UART dongle like this: http://www.ebay.com/itm/6Pin-USB-2-0-to-TTL-UART-Module-Serial-Converter-CP2102-STC-Replace-Ft232-Module-/400565980256?pt=LH_DefaultDomain_0&hash=item5d4397cc60 until it arrives I would love to get this to work...

I hope you have any Ideas (or skype, facebook :D)

If your solution workes with the Arduino - a bigger group of interessted people can benefit of yours and gkaindls work.

EDIT: OGM... I see it... in the &program_tv_edge_color there is something called "activate"... I'll test this one now

Phil1988 commented 10 years ago

Ok i receive something now :D Please note it somewhere for dummies (haha)

can you tell me what kind of data the UART is transmitting? I want to you the Fast-SPI library http://code.google.com/p/fastspi/ to control the LEDs but dont know how to "translate" the received Data to a usable one for the Fast-SPI. I print out the incomming data(bytes) to the Serialmonitor of my Arduino and it looks like : ×Í]̺ͺ®7×cÓåsݎncÊ:®G.......

I hope you can help me

stozze commented 10 years ago

Only one sink can be active per program, so you need to change e.g:

&program_mood_light {
   activate          &timer-30fps
   activate          &mood-light
   activate          &led-frame
}

into

&program_mood_light {
   activate          &timer-30fps
   activate          &mood-light
   activate          &led-frame-uart
}

The uart sink just sends a stream of bytes, GRB, so each led will be 3 bytes (green+red+blue), just like the lpd8806.

The microcontroller I used was a dsPIC30F4013 (running at ~120MHz), that I had lying around in my components bin. I used the spi module on the microcontroller to bitbang the data to ws2811. Getting the timing right was a pain in the a**, but with some trial and error I got it to accept the data (an oscilloscope is a huge help). I will upload the source code for the microcontroller in the very near future along with more details on how my setup looks. I guess it can be ported to Arduino too, but I haven't worked with Arduino at all. Still the main challenge is getting the timing right, there are not a lot of clock cycles to spare when you need to receive and parse uart data and also keep refreshing the ws2811.

Phil1988 commented 10 years ago

For testing I checked the incoming byte from the Pi and printed them to the Serial-Monitor. The active component is now led-uart-frame.

therefore I changed LED settings in the sample config to this (for a test of 27 LEDs) :

leds-top 6-13 # left-to-right leds-bottom 26-19 # left-to-right leds-left 5-0 # top-to-bottom leds-right 14-18 # top-to-bottom

The testing print shows me something like this (testet with 27 LEDs and a static picture on the screen)

LED 0: g byte: 0, r byte: 128, b byte: 128 LED 1: g byte: 64, r byte: 64, b byte: 32 LED 2: g byte: 32, r byte: 16, b byte: 16 LED 3: g byte: 8, r byte: 8, b byte: 4 LED 4: g byte: 4, r byte: 2, b byte: 2 LED 5: g byte: 1, r byte: 1, b byte: 128 LED 6: g byte: 128, r byte: 64, b byte: 64 LED 7: g byte: 32, r byte: 32, b byte: 16 LED 8: g byte: 16, r byte: 8, b byte: 8 LED 9: g byte: 4, r byte: 4, b byte: 2 LED 10: g byte: 2, r byte: 2, b byte: 1 LED 11: g byte: 1, r byte: 0, b byte: 128 LED 12: g byte: 128, r byte: 0, b byte: 64 LED 13: g byte: 64, r byte: 32, b byte: 32 LED 14: g byte: 16, r byte: 16, b byte: 8 LED 15: g byte: 8, r byte: 4, b byte: 4 LED 16: g byte: 2, r byte: 2, b byte: 1 LED 17: g byte: 1, r byte: 0, b byte: 0 LED 18: g byte: 128, r byte: 128, b byte: 64 LED 19: g byte: 64, r byte: 32, b byte: 32 LED 20: g byte: 16, r byte: 16, b byte: 8 LED 21: g byte: 0, r byte: 128, b byte: 128 LED 22: g byte: 64, r byte: 64, b byte: 32 LED 23: g byte: 0, r byte: 128, b byte: 128 LED 24: g byte: 64, r byte: 64, b byte: 32 LED 25: g byte: 32, r byte: 80, b byte: 16 LED 26: g byte: 8, r byte: 8, b byte: 4

next loop with the same, stativ screen picture as before:

LED 0: g byte: 4, r byte: 10, b byte: 2 LED 1: g byte: 1, r byte: 1, b byte: 0 LED 2: g byte: 0, r byte: 128, b byte: 128 LED 3: g byte: 64, r byte: 64, b byte: 16 LED 4: g byte: 16, r byte: 136, b byte: 168 LED 5: g byte: 0, r byte: 128, b byte: 128 LED 6: g byte: 64, r byte: 64, b byte: 32 LED 7: g byte: 32, r byte: 80, b byte: 16 LED 8: g byte: 8, r byte: 8, b byte: 4 LED 9: g byte: 4, r byte: 10, b byte: 2 LED 10: g byte: 1, r byte: 5, b byte: 0 LED 11: g byte: 0, r byte: 128, b byte: 128 LED 12: g byte: 64, r byte: 64, b byte: 16 LED 13: g byte: 16, r byte: 136, b byte: 168 LED 14: g byte: 0, r byte: 128, b byte: 64 LED 15: g byte: 32, r byte: 160, b byte: 16 LED 16: g byte: 16, r byte: 40, b byte: 8 LED 17: g byte: 4, r byte: 4, b byte: 2 LED 18: g byte: 2, r byte: 1, b byte: 1 LED 19: g byte: 0, r byte: 1, b byte: 128 LED 20: g byte: 128, r byte: 32, b byte: 32 LED 21: g byte: 0, r byte: 128, b byte: 128 LED 22: g byte: 64, r byte: 64, b byte: 32 LED 23: g byte: 32, r byte: 16, b byte: 16 LED 24: g byte: 8, r byte: 40, b byte: 4 LED 25: g byte: 4, r byte: 10, b byte: 2 LED 26: g byte: 5, r byte: 5, b byte: 0

Normally the LEDs should have the same byte values on the next loop.... any ideas what is wrong here?

stozze commented 10 years ago

The configuration of led positions looks wrong. Try reading the section about leds-top, leds-left, leds-bottom, leds-right values again, it is a bit tricky to get right. But anyway, the output should be the same even if that is wrong as long as the test image doesn't change.

I think you must implement the serial receive function as an interrupt routine. I do not know how large the fifo buffer on the Arduino is, but if it overflows and bytes as missed, then that would explain why your loops contain different values.

On my dsPIC I made it like this:

  1. uart receive is handled by an interrupt routine (which will save the incoming byte to a buffer), this function should be as fast as possible. dsPIC has a 4 byte fifo buffer on uart.
  2. a timer interrupt will trigger every 100 ms. And if nothing has been received during this time, the receive buffer index would be reset to zero, so the next received byte would be saved as byte number 1 (led 0, green). This helps so we can keep the microcontroller in sync with the PI.
  3. main loop would just update the ws2811 with data from the receive buffer

Because of all critical timings here, we do not have a lot of extra clock cycles to spare. Everything should be as fast and light as possible.

Have you got the ws2811 leds working using the Arduino? This might be an even bigger challenge.

Phil1988 commented 10 years ago

My LED stripe starts at the lower left side, going up and then around the TV. The setting above is just a test setting - so there shouldnt be a problem by a wrong configuration.

Because you asked: Controlling WS2811 (WS2812B in my case) LEDs with Arduino is no problem. It can handle it as you can see in this video I made: http://www.youtube.com/watch?v=lqsIhoUACpw

So it looks like the bigger challenge to me is the receiving of the GRB data...

A helping person noticed that every byte that I receive is made by one or maximum two bits (0, 1, 2... or 8+2=10 etc...). Maybe that could be a hint of what the problem is? I will check if someone in the arduino forum knows more about its fifo and let you know. EDIT: the input buffer is 64 Bytes

In general, I let the Arduino "listen" to the RxD ( if (PiSerial.available())) and if something is incoming, the Arduino runs threw the numbers of LEDs and read 3 bytes of the incoming data for every LED and save this value to the led array.

Phil1988 commented 10 years ago

I got it!

mostly it does what it should. But there are some things that are not a 100% of what it should be like. On booting the PI the LEDs start to flicker sometimes.. It first happens when the screen shows this: http://img818.imageshack.us/img818/4480/l7oj.jpg

I tried to stop this by deleting the part "console=ttyAMA0,115200 kgdboc=ttyAMA0,115200" in the boot/cmdline.txt but it doenst solve it completely. The UART (PIN8 i think) is still sending something at booting.

I dont know if that is the reason, but at testing the last days, two of my LEDs (the first one in the row) broke down.

I also wondered if and how i can exit from ambi-tv as it has started. Also it would be great if the Arduino can stop the PI on running ambi-tv (as it is not used the PI chill a litte :-D )

Is there any testing program around, which can show colors etc. to the edges so that i can check the accuracy? The windows always have that border that makes it hard to test - especially the upper side of the screen.

stozze commented 10 years ago

Is there something like "T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100" inside /etc/inittab? Comment that one out if there is such an entry and reboot.

Yeah I too was missing something like a color test source when testing, but you can do a quick hack to the moodlight source component (or in the sink) so it will only output a single solid color.

You should be able to exit ambi-tv with Ctrl + C if it is running in foreground.

Weird that two of your leds broke, overvoltage/esd perhaps?

Phil1988 commented 10 years ago

Overvoltage is nearly impossible... it also do not explain why always the first LED gets broken (and no other). Maybe the Signals at boot come to weird (to fast.. wrong values) for the first controller and damage it...?

you are right... I have outcommented "T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100" before for testing - but since then I flashed the SD card and forgot to do it again.. (I will try later on if there is still some flickering on boot process)

The moodlight does work.. also the average color... For the edge color I am searching for something like a fullscreen programm where I can put some color boxes... or something similar... Maybe this one can be handy: http://www.youtube.com/watch?v=8cpQpGYtjR0 (at 2:50)

where can I get it from?

For everyone who is interessed as well in ths soulution: as far as I am now - nothing more is needed than an Arduino and some wires.

You did really great with that sink stozze! I thank you and george for this!

Hackmodford commented 10 years ago

Does it end up being cheaper using an Arduino to drive the LEDs?

Phil1988 commented 10 years ago

The PI is still needed on this solution. The Arduino has by far not enough speed to do this and also mussing USB etc...

But with an Arduino and the WS2812B LEDs (which are what i found a bit cheaper than the LPD8806 or WS2801 leds and the color looks better) you will be at nearly the same price like the "original" version. The good think (additional to better colors) is that you can easiely add color effects to the arduino and control them for example with a smartpone over bluetooth... Its a bit more flexible to me, because the PI stuff is to difficult for me :D

Hackmodford commented 10 years ago

Sorry, I was already aware that the raspberry pi was still needed in addition to the Arduino. If you think the WS2812B LED's look better than this seems like a better option, but it adds to the complexity. Are you planning on posting your Arduino code on github?

Phil1988 commented 10 years ago

never used github before so im not sure how to do it... maybe a pull request from stozze?!

But first its important to get to know the issues I reported obove... (need you stozze :D )

Hackmodford commented 10 years ago

Dude you're using it right now ;) Try creating a new repository and uploading your Arduino code.

Phil1988 commented 10 years ago

The LEDs still lights up on booting - but there is no flickering ... I took the GPIO14 (TXD) from the PI... as you can see here: http://elinux.org/images/2/2a/GPIOs.png

boot/cmdline.txt and /etc/inittab are already changed....

The led turn on at this process: [ 9.962991] EXT4-fs (mmcblk0p2): re-mounted. Opts:(null) [....] Checking root file system...fsck from util-linux 2.20.1 /dev/mmcblk0p2: clean, 115429/245760 files, 576764/952704 blocks done.

its weird because the "mmcblk0p2" exists in /boot/cmdline.txt which i have modified like its said here: http://www.hobbytronics.co.uk/raspberry-pi-serial-port

any ideas how to stop sending data to TXD on boot up?

EDIT: I found something that I do not completely understand... The problem is that something is decompressing at bootup I have to compile/decompress a kernel ?!?! http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=53479 http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=33042&p=283774&hilit=uncompressing+kernel

I dont know how I should make this.

Phil1988 commented 10 years ago

this is where i am now...

http://www.youtube.com/watch?v=5zYz_Vd1VEM starting with average color, then to moodlight and on 0:14 the edge ambilight... testing with black desktop of my computer with some icons on it... as you can see in the video - top and bottom are flickering... the problem I have now is that the LEDs are flickering a litte even if there is nothing movin on the screen...

video stream looks like this: http://www.youtube.com/watch?v=EsQW5cM58RM

stozze commented 10 years ago

I too had some flickering in the beginning but tuning the gamma (all set to 2.2) and crop values solved it. In my case, the cause of the problem was that there were a lot of noise on the input stream from the USB video capture device.

Problems went away when I used 360x288 frames on /dev/video0 and the following values in config:

v4l2-grab-source {
   name                          v4l2-video
   video-device                  /dev/video0
   buffers                       4
   crop-left                     4
   crop-top                      3
   crop-right                    4
   crop-bottom                   3
   autocrop-luminance-threshold  24
}

and this for edge processor:

edge-color-processor {
   name              edge-color
   box-width         12
   box-height        12
}
Phil1988 commented 10 years ago

Hmm... I have no noise in the input stream: http://www.youtube.com/watch?v=Ed_3CiAvr3o

I have nearly the same settings as you... dark szenes or dark blue is often cause some flickering.

How did you set 360x288 frames ? I tried a lot with gamma and finaly stoped at 2.0 Bad thing is that brown/skin becomes red for the LEDs and sand/beige becomes orange light. beside this the colors are really close to the goal.

Hope you can tell how to change the resolution for /dev/video0 Cheers!

stozze commented 10 years ago

Install the v4l-utils package (# sudo apt-get install v4l-utils) then use v4l2-ctl to change resulution/settings before starting ambi-tv:

# v4l2-ctl --set-fmt-video=width=360,height=288,pixelformat=1

Use "v4l2-ctl --list-formats" to get a list of available pixelformats for your device, on mine index 1 was YUYV.

Phil1988 commented 10 years ago

I will test it tonight.

This is how far I am now: http://www.youtube.com/watch?v=Sq8Z6zaDfZU

dark blue makes big problems..

stozze commented 10 years ago

@gkaindl Could you please close this pull request, if you are not going to merge it, thanks.

washcroft commented 10 years ago

@Phil1988 Where do you get up to with this? I'm in the same position, would love to use @stozze 's UART sink to pass the values to an Arduino.

Phil1988 commented 10 years ago

I ended at hyperion as the colors of ambilight dont match to the screen.