Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 43 of 43

Thread: Arduinoesque overriding of core functionality

  1. #26
    Junior Member
    Join Date
    Oct 2014
    Posts
    12
    As I said before I don't want to promote this by making it easy to use until it's been tested. Using the example in the README should be sufficient to start using it. For example:

    Code:
    #define DMX_REDE 30
    struct RDMINIT rdmData {
      "TeensyDMX v0.1",
      "Teensyduino",
      1,  // Device ID
      "DMX Node",
      1,  // The DMX footprint
      0,  // The DMX startAddress - only used for RDM
      0,  // Additional commands length for RDM
      0   // Definition of additional commands
    };
    TeensyDmx Dmx(Serial2, &rdmData, DMX_REDE);
    
    void setup() {
      Dmx.setMode(TeensyDmx::Mode::DMX_IN);
    }
    
    void loop() {
      Dmx.loop();
    
      if (Dmx.newFrame()) {
        volatile const uint8_t *buf = Dmx.getBuffer();
        // Do something with the buffer
      }
    }

  2. #27
    Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    20
    Hi All,
    Sorry to have been absent from this thread...honestly, it was a bit of a fire-and-forget. I'm glad (and more than a little humbled) that folks have taken this on, and I'm fine with the repackaging and licensing. I am far from a software guy, more like a hardware guy who got frustrated with the lack of a DMX receive library and wrote some hack code. Next time I'll wrap some more words around it like "Works fine with ETC Express 48/96 serial number XXXX, your mileage *will* vary." I have no doubt that there are DMX implementations that break it, and I apologize if that's caused anyone heartburn. I seem to remember being particularly nervous about minimal-length MBB (mark before break) or break periods, and it sounds like that's been an issue. I also don't claim to have employed sound coding practices, so Jim and Chris' efforts to clean up my mess are especially appreciated.

    For what it's worth, I've used this code to drive LED pixel strings in the theater for a number of shows, and am looking forward to trying out some of the updates. The theaters I work in all run the same lighting console, an ETC Express, so I'm afraid I can't offer much in the way of interesting DMX implementations to test against. Also, for my Christmas lights this past year I put together a new controller that I'm going to start using in the theater and I'll gladly share details on. It uses standard Ethernet cabling (RJ45-terminated cat 5/5e/6) to wire the LED strings back to the controller, running +24VDC and balanced (RS-422) WS2811 protocol over the wire. I've successfully tested runs of 200 feet from the controller to the head of the string, with good integrity on the WS2811 signal.
    Last edited by Ward; 02-11-2015 at 05:53 AM.

  3. #28
    Hi everyone

    does someone can post here the schematics needed to read DMX frame with the jim paris's library ?

    thank you

  4. #29
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,115
    All you should need is a RS-485 chip wired for receive-only mode.

    The 8 pin ones almost all use the same pinout. Pin 1 is the output, which you'd connect to RX1 on Teensy. Pin 2 is RE', which you'd connect to ground to enable the receiver. Pins 3 and 4 are for the transmitter. Connect pin 3 to ground so the transmitter is disabled. Pin 4 can be left unconnected. Pins 5 and 8 are for power, and pins 6 and 7 are the signal lines for the DMX.

    That's not a schematic... but hopefully it gives you enough info to wire up any of those 8-pin RS485 chips.

  5. #30
    Here's a section of the design where I'm using it:
    Click image for larger version. 

Name:	teensy-dmx.png 
Views:	1568 
Size:	82.8 KB 
ID:	4229

  6. #31
    Hello again Paul (and thank you again !!)

    I finished my board, but when try to compile, I have the error : error: 'IRQ_UART0_ERROR' was not declared in this scope

    Teensyduino is set as serial, do you have an idea ?

    there's the code :
    Code:
    /* DmxReceiver DmxTest.ino - DMX Test
       Copyright (c) 2014 Jim Paris
    
       Permission is hereby granted, free of charge, to any person obtaining a copy
       of this software and associated documentation files (the "Software"), to deal
       in the Software without restriction, including without limitation the rights
       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       copies of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:
    
       The above copyright notice and this permission notice shall be included in
       all copies or substantial portions of the Software.
    
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       THE SOFTWARE.
    
       Required Connections
       --------------------
       pin 0: DMX in (from RS485 transceiver)
    
       This test prints out DMX data to USB serial every 1 second.
       The on-board LED is toggled every time a DMX frame is received.
    */
    
    #include <DmxReceiver.h>
    
    DmxReceiver dmx;
    IntervalTimer dmxTimer;
    
    void dmxTimerISR(void)
      {
      dmx.bufferService();
      }
    
    void setup() 
      {
      /* USB serial */
      Serial.begin(115200);
    
      /* DMX */
      dmx.begin();
    
      /* Use a timer to service DMX buffers every 1ms */
      dmxTimer.begin(dmxTimerISR, 1000);
    
      pinMode(LED_BUILTIN, OUTPUT);
      }
    
    int led = 0;
    elapsedMillis elapsed;
    void loop()
      {
      /* Toggle LED on every new frame */
      if (dmx.newFrame())
        {
        led = !led;
        digitalWrite(LED_BUILTIN, led);
        }
    
      /* Dump DMX data every second */
      if (elapsed > 1000) 
        {
        elapsed -= 1000;
        Serial.printf("DMX frameCount=%d", dmx.frameCount());
    
        /* Display all nonzero DMX values */
        for (int i = 0; i < 512; i++) 
          {
          uint8_t v = dmx.getDimmer(i);
          if (v)
            {
            Serial.printf(" %d:%d", i, v);
            }
          }
        Serial.printf("\n");
        }
      }

  7. #32
    Quote Originally Posted by jimparis View Post
    Here's a section of the design where I'm using it:
    Click image for larger version. 

Name:	teensy-dmx.png 
Views:	1568 
Size:	82.8 KB 
ID:	4229
    Yes thanks a lot !

  8. #33
    Hi there,

    New try, I see that a file named "mk20dx128.h" was called in the jim's library, but the teensy LC has a mkl26z64
    Does it means that the library cannot work with Teensy LC ?

    I also tried to add these lines in the dmxReceiver.cpp
    Code:
    #define IRQ_UART0_LON   15
    #define IRQ_UART0_STATUS  16
    #define IRQ_UART0_ERROR   17
    #define IRQ_UART1_STATUS  18
    the code now seems valid, but the board doesn't seems to be alive (the first line of my setup is not runned);

  9. #34
    It looks like the MKL26Z64 doesn't separate the UART0 interrupts like the MK20DX128 did, so properly catching the BREAK condition (frame error) will require modifications to the Teensy core code. Which is really the right way to do it anyway. I just don't know what the best interface is to expose it -- a weakly linked callback?

  10. #35
    Quote Originally Posted by jimparis View Post
    It looks like the MKL26Z64 doesn't separate the UART0 interrupts like the MK20DX128 did, so properly catching the BREAK condition (frame error) will require modifications to the Teensy core code. Which is really the right way to do it anyway. I just don't know what the best interface is to expose it -- a weakly linked callback?
    Ok I understand absolutely nothing (And I'm a little scared when I see "modifications to the Teensy core code" )
    I don't understand why dmx cannot be readed like a serial data (yes yes, I'm noob...)

  11. #36
    Junior Member
    Join Date
    Jun 2015
    Posts
    9
    Hi Jim,

    So I am a bit new to all this too, and was wondering if it would be possible (for me) to adjust the library you modified, so that I could use serial 3 on a Teensy 3.1? this is because I made a bit of a mistake and had a PCB made for a project that includes DMX receiving, and wired the MAX 485 to use the Serial 3 Port on my teensy, and obviously now, it doesn't receive nothing :s could you guide me on where to change this? I have looked on the .cpp and .h files and I see UART0 in a lot of places, I guess I have to change all of that to UART3... ??? any guideance would be greatly appreciated.

    cheers,

  12. #37
    Quote Originally Posted by Cristobal View Post
    Hi Jim,

    So I am a bit new to all this too, and was wondering if it would be possible (for me) to adjust the library you modified, so that I could use serial 3 on a Teensy 3.1? this is because I made a bit of a mistake and had a PCB made for a project that includes DMX receiving, and wired the MAX 485 to use the Serial 3 Port on my teensy, and obviously now, it doesn't receive nothing :s could you guide me on where to change this? I have looked on the .cpp and .h files and I see UART0 in a lot of places, I guess I have to change all of that to UART3... ??? any guideance would be greatly appreciated.

    cheers,
    I'd start by changing HardwareSerial() to HardwareSerial3(), then change all the UART0 to UART2 (UART2 is serial 3). Might work!

  13. #38
    Junior Member
    Join Date
    Jun 2015
    Posts
    9

    Post

    Quote Originally Posted by jimparis View Post
    I'd start by changing HardwareSerial() to HardwareSerial3(), then change all the UART0 to UART2 (UART2 is serial 3). Might work!
    Hey Jim,

    Thanks for the quick response, So I tried that, changed the HardwareSerial() to HardwareSerial3() (I also tried ...serial2()) and everywere I could see UART0, I changed to UART2, but it still wont work
    I did try with no modification and using Serial 1 and it works like a charm, so my wiring is correct.

    There is 2 lines in your code that have a UART0 but if I change that, it wont complie, telling me that those expressions have not been defined, these are:


    if (UART2_S1 & UART_S1_FE)

    and

    UART2_C3 |= UART_C3_FEIE;

    as I mentioned before, my programming skills are very basic, so I dont really understand what those expressions actually mean

    anyways, here is my modified code, I dont know if you have the patience and will to give it a read and tell me where am I messing up.

    Thank you very much again for the help.

    Code:
    /* DmxReceiver - DMX Receiver for Teensy 3
       Copyright (c) 2014 Jim Paris
       Copyright (c) 2014 Ward
    
       Permission is hereby granted, free of charge, to any person obtaining a copy
       of this software and associated documentation files (the "Software"), to deal
       in the Software without restriction, including without limitation the rights
       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       copies of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:
    
       The above copyright notice and this permission notice shall be included in
       all copies or substantial portions of the Software.
    
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       THE SOFTWARE.
    */
    
    #include "mk20dx128.h"
    #include "DmxReceiver_CrisEdit.h"
    #include "HardwareSerial.h"
    
    #define DMX_BUFFER_SIZE 513
    
    #ifndef UART_C3_FEIE
    #define UART_C3_FEIE    (uint8_t)0x02   // Framing Error Interrupt Enable
    #endif
    
    static volatile uint8_t dmxBuffer1[DMX_BUFFER_SIZE];
    static volatile uint8_t dmxBuffer2[DMX_BUFFER_SIZE];
    static volatile uint8_t *activeBuffer;
    static volatile uint8_t *inactiveBuffer;
    static volatile uint16_t dmxBufferIndex;
    static volatile unsigned int frameCount=0;
    static volatile bool newFrame=false;
    HardwareSerial Uart = HardwareSerial2();
    
    void DmxReceiver::begin(void)
    {
            // UART Initialization
            Uart.begin(250000);
    
            // Fire UART0 receive interrupt immediately after each byte received
            UART2_RWFIFO = 1;
    
            // Set error IRQ priority lower than that of the status IRQ,
            // so that the status IRQ receives any leftover bytes before
            // we detect and trigger a new frame.
            NVIC_SET_PRIORITY(IRQ_UART2_ERROR,
                              NVIC_GET_PRIORITY(IRQ_UART2_STATUS) + 1);
    
            // Enable UART0 interrupt on frame error and enable IRQ
            UART2_C3 |= UART_C3_FEIE;
            NVIC_ENABLE_IRQ(IRQ_UART2_ERROR);
    
            activeBuffer = dmxBuffer1;
            inactiveBuffer = dmxBuffer2;
    }
    
    void DmxReceiver::end(void)
    {
            Uart.end();
            NVIC_DISABLE_IRQ(IRQ_UART2_ERROR);
    }
    
    void DmxReceiver::fill(uint8_t v)
    {
            __disable_irq();
            dmxBuffer1[0] = 0;
            memset((void *)(dmxBuffer1 + 1), v, DMX_BUFFER_SIZE - 1);
            dmxBuffer2[0] = 0;
            memset((void *)(dmxBuffer2 + 1), v, DMX_BUFFER_SIZE - 1);
            __enable_irq();
    }
    
    void DmxReceiver::clear(void)
    {
            fill(0);
    }
    
    unsigned int DmxReceiver::frameCount(void)
    {
            return ::frameCount;
    }
    
    uint8_t DmxReceiver::getDimmer(uint16_t d)
    {
            return inactiveBuffer[d];
    }
    
    int DmxReceiver::bufferService (void)
    {
            __disable_irq(); //Prevents conflicts with the UART0 error ISR
            int available=Uart.available();
            int retval=available;
            while (available--)
            {
                    activeBuffer[dmxBufferIndex]=Uart.read();
                    if (dmxBufferIndex<(DMX_BUFFER_SIZE-1)) dmxBufferIndex++;
            }
            __enable_irq();
            return retval;
    }
    
    bool DmxReceiver::newFrame(void)
    {
            if (::newFrame)
            {
                    ::newFrame=false;
                    return true;
            }
            return false;
    }
    
    // UART0 will throw a frame error on the DMX break pulse.  That's our
    // cue to switch buffers and reset the index to zero
    void uart2_error_isr(void)
    {
            // On break, uart0_status_isr() will probably have already
            // fired and read the data buffer, clearing the framing error.
            // If for some reason it hasn't, make sure we consume the 0x00
            // byte that was received.
            if (UART2_S1 & UART_S1_FE)
                    (void) UART2_D;
    
            // Ensure we've processed all the data that may still be sitting
            // in software buffers.
            DmxReceiver::bufferService();
    
            // Update frame count and swap buffers
            ::frameCount++;
            dmxBufferIndex = 0;
            if (activeBuffer == dmxBuffer1)
            {
                    activeBuffer = dmxBuffer2;
                    inactiveBuffer = dmxBuffer1;
            }
            else
            {
                    activeBuffer = dmxBuffer1;
                    inactiveBuffer = dmxBuffer2;
            }
            ::newFrame=true;
    }

  14. #39
    There is 2 lines in your code that have a UART0 but if I change that, it wont complie, telling me that those expressions have not been defined
    That's strange. With Arduino 1.0.5 + Teensyduino 1.18, and with Arduino 1.6.4 + Teensyduino 1.23, your code compiles just fine (with those lines). Maybe try upgrading to the latest Teensyduino?

    Besides that, I don't have any ideas, sorry. There may be differences in the way the UART0 and UART2 hardware is implemented in the chip that affects how we're using it here, but I don't have a test setup at the moment where I can look into that further.

  15. #40
    Junior Member
    Join Date
    Jun 2015
    Posts
    9
    Yeah, the code "as is" compiles fine, but if I change

    if (UART2_S1 & UART_S1_FE)

    to

    if (UART2_S1 & UART2_S1_FE)

    is when it wont compile...

    well, thanks a lot for the help man, I don't know if Paul could have a little bit more insight as on what could be done, cause your library is awesome, and it would be sweet if it could be used with any of the 3 UART ports the Teensy 3.1 has.

    Cheers

  16. #41
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    171
    Breaks detected via framing errors do indeed return a zero in the data byte, however because DMX also requires knowledge of non-zero bytes from framing errors—for being able to detect bad data and throwing the frame away—a better solution might be to register some framing error handler that includes the data byte. But this feels like too special a case and not a flexible enough case for doing proper break detection by adding this error handler to the API. (In reference to Paul's question about an API addition.)

    I'll also add that without using an extra pin to do RX signal edge detection, it's hard to detect longer breaks. The best I've been able to do is detect BREAK plus Mark after Break (MAB) time, together but not separate. In other words, if we just use the serial port, all we know is when the start of a break (having a zero data byte) occurred by subtracting one character time, and when the MAB ended by detecting a byte received and also subtracting one character time.

    See the TeensyDMX project for some example code for all this. (Sorry for all the #defines. I'm attempting to avoid duplicate code for 7 serial ports.) Note that it uses its own ISRs and not the built-in serial API.

  17. #42
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    11,826
    Quote Originally Posted by Cristobal View Post
    Yeah, the code "as is" compiles fine, but if I change

    if (UART2_S1 & UART_S1_FE)

    to

    if (UART2_S1 & UART2_S1_FE)

    is when it wont compile...
    ...
    From a quick glance at the kinetis.h header it looks like this is just a constant used to check the indicated flag::
    Code:
    #define UART_S1_FE		0x02			//  Framing Error Flag
    So the first line that compiles should be the correct one to check that flag where UART[#]_S1 just refers to // UART Status Register [#]

  18. #43
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,379
    the uart register of the first field is different per UART port, however, the second field is common among all UART registers.

    UART_S1_FE is valid for all status registers of UARTs, theyre all shifted the same way down the register map

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •