On Wed, 28 May 2014 22:52:35 +0100
jon <
j...@jonshouse.co.uk> wrote:
Sorry for the delay getting back to you on this - I have been
> I do not know OLA in any detail, so have need to read my way through
> the source tree to know where to find the code. I am also not a great
> fan of c++ hence my lack to desire to poke around in the OLA
> codebase :-)
All in the plugins/uartdmx/ directory within the source. It's mostly a
copy of the FTDI output module, but tweaked to use the standard UART
calls rather than the FTDI-specific library. I started off with a
stand-alone C demo program which I should be able to find and send to
you if it's useful.
> I did work out what I did wrong with my UART code but have not fixed
> it yet. I forget to toggle the GPIO pin between the UART and GPIO
> modes, as a result the BREAK and MAB I generated performed no action
> - though it did output the serial stream at the correct 250k bit.
Bit confused by this - you should be able to generate BREAK and MAB
with ioctls() to the UART without any extra gpio pins needed.
> I added this to the little Pi gpio interface I was using:
>
> // Set a (possibly high) baud rate without linux kernel knowing about
> it. Useful for DMX maybe ? // To get 250k buad you must add
> "init_uart_clock=16000000" to /boot/config.txt and pass 4,0 to this
> function set_baudrate_divisors(unsigned int divisorwhole, unsigned
> int divisorpartial) { *(gpio+1024) = divisorwhole;
> *(gpio+1028) = divisorpartial;
> }
You can select 250kbaud mode in a slightly more standard way (it works
for any (supported) UART on Linux, but only on Linux) with the termios2
interface (which accepts baud rate as an integer in bits per second,
rather than symbolic constants). This is in UartLinuxHelper.cpp in my
sources, which is really just a C function wrapped up into a static
method.
> Its all pretty crude, I suspect I can make it work if I put a couple
> of hours into it but I got distracted with other projects.
>
> The one problem I cant see a solution for is that when outputting the
> DMX values the Linux scheduler could come back late and fail to fill
> the UART in time, do you see any flashes from your code (miss timed
> packets) or does it look rock solid?
It's rock solid for me, with the proviso that I know the LED fitting I
am using will hold state indefinitely if the DMX input is removed (it
doesn't drop back to black on no signal). So I am confident that the
513 bytes of DMX lighting data go out as a block, with no glitches in
them. I agree that the parts of the waveform timed by the Linux
userspace scheduler may be late, but this should only affect the
durations of the break, mark-after-break and inter-frame gaps (the
things timed with usleep()). The DMX spec is (I think) relatively
forgiving about the upper limit of these timing elements - certainly
the timing does vary, you can see this if you have a 'scope on the DMX
line.
What has to be consistent is the run of 513 bytes in a frame,
which have to be (close to) back to back in order to stop the devices
dropping out of lock and reading the rest of the frame as a new frame
(which certainly will flicker!). I think this shouldn't be a problem
using the Pi's built-in UART, because the UART has both a hardware
buffer and a direct interrupt line from the UART to the processor (they
being on the same chip!).
So when my code calls write(), 513 bytes go
into a buffer in the Linux kernel. The kernel driver for the UART then
pushes 16 bytes out to the hardware UART, which starts putting them on
the wire. As that 16 byte buffer empties, an interrupt is raised by the
UART to get it re-filled. This causes the Linux kernel to stop what it
is doing, and put some more of the 513 byte kernel buffer contents into
the 16 byte UART buffer, and repeat until all is done. This is all done
in kernel mode, and I think all in an interrupt (I haven't looked at
the actual driver, but would expect this to be the case). As a result,
the user space scheduler doesn't come into it, and the only question is
what the IRQ latency of the Linux kernel on the Pi is - which I would
expect to be very small compared to the time taken to push out 16 bytes
at 250kbaud (576 microseconds, if my maths is right).
This argument doesn't work for USB-connected serial adaptors, because
they don't have hardware interrupt lines - they rely upon the USB host
controller polling the peripherals, which inevitably has higher
latency. So you need bigger buffers in the USB peripheral, or you get
glitches in the output when the USB doesn't fill the buffer in the
serial converter in time. I haven't played with this, but I can see
it's much harder to get to work.
The disadvantage is you can only have one UART on the Pi because that
is all the hardware there is - your approach can be scaled up because
there are more GPIO pins.
I was wondering about using the GPIO blaster technique to produce
analogue outputs from the Pi, so it could act as an
ethernet-to-analogue-dimmer bridge unit (like a DMX demux, but
straight from Ethernet) ...
Richard