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

Thread: Arduinoesque overriding of core functionality

  1. #1
    Junior Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    11

    Arduinoesque overriding of core functionality

    I'm working on a project that uses UART0 for reception of DMX512 serial data and have everything working at this point, but in order to do that I had to significantly modify a few core files: mk20dx128.h, serial1.c, and hardwareserial.h in order to change the uart status ISR and serial buffer structure. I could distribute the code as-is, with instructions to replace those files with my own, but that would semi-permanently change the behavior of the core code, which I consider to be bad form. I was wondering if there's provision within the Arduino (or Teensy) build system to provisionally replace those sections of code without resorting to modification of any of the default installation. I note that that's generally done for ISRs using the __attribute__ keyword to weakly bind default code segments, but once the ISR's been established within serial1.c it looks to be a strong binding. Are there any other options?

  2. #2
    Junior Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    11
    I suppose one option would be to distribute new files with a bunch of #ifdefs or similar. That would prevent breaking the default functionality, but would still require touching the core code.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,699
    I am willing to add code to Teensy's core library, to support break detection for the sake of DMX receive. Ideally it should not make the Serial any slower for normal programs that do not require break detection. I'm sure it will increase the code size, but hopefully that can be minimized.

    I'm planning to release 1.13 within the next week or two. Do you have something I should consider merging for 1.13?

  4. #4
    Junior Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    11
    Thanks for the quick response...on a Sunday morning, no less! The break detection's actually using the UART's frame error detection to trigger on the missing stop bit. It's a hack, but if you're seeing frame errors that aren't due to the break then you've got bigger problems. At any rate, when the frame error interrupt trips, the ISR resets the buffer pointer. It's really straightforward, and that part doesn't require touching the core serial library.

    I think the biggest change to the core code is that I'm using a 513 byte buffer that's *not* a ring buffer...if the index runs over for some reason, it spins on buffer[512] to prevent poisoning the rest of the buffer. That's pretty different from your 32 byte ring buffer implementation, which makes perfect sense for general-purpose serial receiving. I don't know what the best way to implement this is, since it's all done in the UART status ISR and can't be overridden. Thoughts?

  5. #5
    Junior Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    11
    I should also add that it's possible to do all of this within the existing structure, just by reading bytes out of the ring buffer and putting them in the DMX buffer. Maintaining two buffers and touching the bytes twice is a bit more expensive but a lot less intrusive. I could certainly be accused of going down the engineer's route of stacking angels on the head of a pin while ignoring the surrounding empty football field. There might also be some nasty race conditions introduced by that approach.

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,699
    I'm hoping for minimally intrusive changes.

    At 250 kbps and 11 bits per byte (1 start, 8 data, 2 stop), each byte takes 44 us. That's plenty of time for a little overhead moving the data between buffers(**). Currently serial1.c has a 64 byte buffer. That's 2.8 ms to overflow the buffer, so you won't be able to do stuff like delay(100). But it should be easily possible to build a DMX controller with Serial1.read() and controls lights as it gets the data, or piles the data up into a 512 byte buffer and uses it when the transmission ends.

    I must confess, I haven't done testing with receiving break signals. My understanding is the existing code should return a single 0 byte for the entire break. Is that right?

    From an API point of view, I can imagine a few ways this might work. Probably the simplest would be a callback function, similar to attachInterrupt(), called when the hardware detects a break. Maybe a reasonable implementation would call that function if there's a framing error and the byte received is zero? Then in your callback function, you could use Serial1.clear() and set up anything your DMX parsing code needs. The one downside is this burdens your application code with interrupt safety issues, but maybe that's ok since this is mostly meant for supporting one protocol.



    ** - on the buffering overhead, probably the worst issue, and one that I'm planning to address eventually, is the lack of an efficient block read function in the Arduino API. DMX is slow enough that the currently available APIs should be fine. Unfortunately, this sort of change probably requires coordinating with the Arduino Team on the official Arduino API... which takes a lot of time to first make the case in public, and once the decision is made, the only way to move forward at any speed is pretty much doing all the work in a pull request for all official Arduino boards too. I might do that someday, but right now I have a lot of other more urgent things (and break support for DMX is on that list).

  7. #7
    Junior Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    11
    All done. It's a shame DorkBot's not tomorrow night, or I'd haul my lighting console down and use it to flash some LEDs using the DMX library and OctoWS2811. To answer your question about breaks, yes, the UART core code registers the break as 0x00.

    The implementation details:
    I did pretty much what you suggest above. I'm actually using two buffers, an "active" one that's being written, and an "inactive" one that contains the contents of the last frame. When each frame completes, the buffers toggle state. This can be done with a single buffer if the user's not concerned with mixing data from two frames.

    Functions in the library:

    void dmx_begin(void);
    Initializes the serial port, sets up the UART error interrupt

    void dmx_end(void);
    Terminates the serial port, disables the UART error interrupt

    int dmx_bufferService(void);
    Transfers bytes from the UART receive FIFO to the DMX buffer. CALL EVERY 2.5MS OR LESS OR THE FRAME DATA WILL BE CORRUPTED. Returns the number of bytes transferred; if it's 64, best to discard the frame. Blocks interrupts for 0-100us.

    uint8_t dmx_getDimmer(uint16_t);
    Get an individual dimmer value

    unsigned int dmx_frameCount(void);
    Get the frame count (can be useful to see if you're dropping frames for some reason)

    bool dmx_newFrame(void);
    Returns true if a new frame has been received since the function was last called
    Attached Files Attached Files

  8. #8
    Junior Member
    Join Date
    Apr 2013
    Posts
    8
    Quote Originally Posted by Ward View Post
    I think the biggest change to the core code is that I'm using a 513 byte buffer that's *not* a ring buffer...if the index runs over for some reason, it spins on buffer[512] to prevent poisoning the rest of the buffer. That's pretty different from your 32 byte ring buffer implementation, which makes perfect sense for general-purpose serial receiving. I don't know what the best way to implement this is, since it's all done in the UART status ISR and can't be overridden. Thoughts?
    It would be a great feature if you could set the buffer size for the receiving part.
    That is you do not always need to read the whole 512 size dmx chunk.
    The parameters might as well be located in the first 20 or so bytes.
    void init_dmx_read(buffersize)

    .F

  9. #9
    Junior Member
    Join Date
    Mar 2013
    Location
    Hillsboro, OR
    Posts
    11
    Quote Originally Posted by klankschap View Post
    It would be a great feature if you could set the buffer size for the receiving part.
    That is you do not always need to read the whole 512 size dmx chunk.
    The parameters might as well be located in the first 20 or so bytes.
    void init_dmx_read(buffersize)

    .F
    An excellent point. It's actually pretty rare to need all 512 channels' information, so keeping tying up 1k of memory for it is pretty wasteful. If I get a chance at some point I'll add another constructor that allows a subset range of channels.

  10. #10
    Junior Member
    Join Date
    Apr 2013
    Posts
    8
    Quote Originally Posted by Ward View Post
    An excellent point. It's actually pretty rare to need all 512 channels' information, so keeping tying up 1k of memory for it is pretty wasteful. If I get a chance at some point I'll add another constructor that allows a subset range of channels.
    A more extended function might be to provide a list of addresses for which only input will be returned.
    e.g. for the address list [1, 2, 3, 42, 123, 420] the interrupt routine will pick out the cherries and return a list of 6 data.

  11. #11
    Junior Member
    Join Date
    Apr 2013
    Posts
    8
    any luck implementing the new snazzy features ?
    .F

  12. #12
    is it possible that this stops other intervalTimer from being called?
    i am writing code for the teensy 3 that dims 16 leds, which works great.
    and the dmxreceiver works great too.
    but when i put them both together i do receive any dmx.

    thanks.

    Code:
    IntervalTimer dimmingTimer;
    
    void dimming_handler2(void) {
    //some dimming code here that uses  digitalWriteFast(ledPin[i],dimStates[i]);
    }
    
    void setup_dimming(){
      dimmingTimer.begin(dimming_handler2, 30);  
    }

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,699
    Quote Originally Posted by stephanschulz View Post
    but when i put them both together i do receive any dmx.
    Please post this in a new topic with the full code. Think in terms of including enough info that someone could reproduce the problem! Or read these guidelines.

  14. #14
    sorry, still learning the right etiquette

  15. #15
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    serial port ring buffer schemes I've done use a ring buffer with an error bit 'buffer overflow' that can be accessed.

    Great debate, and perhaps a run time option choice, on whether to wrap the buffer (ring) or discard data when buffer fills. Making it a run time option lets the app choose.
    Some systems also let the app provide the buffer at port open time, in case the app wants an unusually large buffer.

  16. #16
    Junior Member
    Join Date
    Dec 2013
    Posts
    2
    Thankyou for the code. I have been playing with it for a week, but I'm getting intermittent results from a commercial artnet-dmx node.

    I borrowed an oscilloscope and learnt about scoping differential signals the hard way. All signals look clean, the 485 transceiver appears to be doing its job, the data is coming into the teensy cleanly and at a reasonable level (my 7407 step down circuit was suffering capacitance issues due to large pull up resistors - fixed now, but same result. Also used a voltage divider to stop the 5v down to 3.3v. No dice). I also tried multiple power supplies, extra bypass caps, etc.

    Today I borrowed another DMX generating device (like a riggers remote), and everything works perfectly with this! Not so with the artnet node.

    I've done some more trouble shooting with sending a channel value back to the serial port - the artnet node often gives alternate values on each frame - ie 40 170 40 170 40 etc. My guess is that this could be something to do with double counting the break, and hence double-swapping registers? I've used the node previously with other devices and it has performed fine (unless I've damaged it through my testing).

    Can anyone think of anything else I am missing here?

    Edit - looking at the scope again, it looks like the break, MAB and slot 0 are all inverted on the artnet node - but then the packets are all fine. I can see how this could confuse the UART. I suppose I should start looking at the artnet node output stage as a first port of call.
    Last edited by Cafengineer; 12-13-2013 at 01:11 PM.

  17. #17
    Junior Member
    Join Date
    Dec 2013
    Posts
    2
    Call off the panic... I just opened up the node and the 485 showed some signs of stress... I probed the DI line and the break and MAB were the correct way around! I connected gnd and the DI line to the teensy directly, and hey-presto, it worked. Guess I'm off to order a new rs485 driver for the node...

  18. #18
    Junior Member
    Join Date
    Sep 2013
    Posts
    13
    When i use this code, it works fine with a simple DMX tester, but when i use it with a art-net to DMX node, the values aren't constant. i get this values ;

    Code:
    37
    37
    37
    37
    37
    37
    37
    0
    37
    37
    37
    37
    37
    0
    37
    37
    0
    37
    0
    37
    0
    0
    37
    0
    37
    37
    0
    37
    0
    0
    37
    0
    37
    0
    37
    0
    0
    0
    how can i solve this?

  19. #19
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,699
    Could you be more specific about "art-net to DMX node".

    Please read these guidelines for asking technical questions....

  20. #20
    Junior Member
    Join Date
    Sep 2013
    Posts
    13
    I use this one ==> http://www.artisticlicence.com/index.php?mode=products&sub=overview&action=&categ ory_id=4&product_id=266&project_id=&policies_id=&c art_id=&order_id=. I send the DMX with Chamsys to art-net.

    I receive it with a teensy 3.0 and the example code of the library. I use the chip max3483, it is the same as a max485 but for 3.3V

    The value "37" is correct, but not the zeros.

  21. #21
    Junior Member
    Join Date
    Apr 2014
    Posts
    5
    hi, i have a problem with dmx Receiver library, the problem is:
    with frystyler 512 i set channel 1 to 40 and channel 2 to 30, when i read channel 2 with teensy 3.1 using the arduino ide i go to serial monitoring and i see 30, but one time i see the value of channel 2 end one time the value of chanel 1 exaple:
    i see in serial monitoring on arduino ide: 30 40 30 40 30 40 30 40, if i change the value of channel 1 from 40 to 77 i see 30 77 30 77 30 77, i only read the channel 2 but it read channel 2 and channel 1
    any solution? i use max485 for convert dmx signal to rs232 and its set ro recive mode onli, (pin 2, 3 to gnd, pin 1 to rx of teensy, pin 6 to dmx pin 3 and pin 7 to dmx pin 2)
    thanks

  22. #22
    Junior Member
    Join Date
    Apr 2014
    Posts
    5
    ad this video to see the problem

    any advice?

  23. #23
    Hi,

    Ward's code has problems with any DMX controller that doesn't have a long MARK time between the last DMX value and the BREAK. Chauvet brand controllers work fine, but my uDMX USB adapter does not. The symptom is that the values in the DMX buffer will be randomly shifted by 1-4 addresses, causing wild flickering and whatnot.

    The problem is because of an interaction between the Teensy software buffer, the hardware FIFO, and Ward's new code. Briefly, a frame error interrupt will be generated whenever a BREAK occurs. In the frame error ISR, any leftover previously-received data is processed by calling dmx_bufferService. However, this only retrieves data that has already been stored into software buffers by the Teensy uart0_status_isr. There may still be other data in the hardware RX FIFO, since
    the default configuration for the Teensy allows up to 4 bytes to get queued before the uart0_status_isr is fired. Right now, that data ends up in the wrong place, the new frame.

    With some controllers, this is not a problem because uart0_status_isr is also fired during a long idle, which may allow the receive FIFO to have been emptied immediately before the BREAK. But this idle period ("mark time between packets" in DMX spec) has no minimum length, so it's perfectly valid for controllers to leave it out.

    Sticking with Ward's approach of trying to work with what we've got, one approach is to set UART0_RWFIFO=1 so that the Teensy uart0_status_isr handler is triggered immediately after each byte. Then some small changes are needed to our uart0_error_isr, since the frame error may already get cleared by the status ISR; other than that it's basically the same.

    Of course, the best solution would be to integrate uart0_error_isr into the Teensy code so that breaks are properly detected and handled in sync with the status ISR.

    I've updated and cleaned up the DmxReceiver code, repackaged it into an Arduino library with example code, and uploaded it to Github: https://github.com/jimparis/DmxReceiver. I also took the liberty of slapping the usual Teensy (MIT) license on the files. Ward, if you don't agree with that, just let me know and I'll fix it.

  24. #24
    Junior Member
    Join Date
    Oct 2014
    Posts
    12
    After working on a DMX project that I wanted send and receive I took the above DmxReceiver library, added in the DmxSimple library and then added RDM from the DMXSerial2 library. I then modified the TX code to make use of the hardware rather than doing bit-banging. It seems to work using the limited hardware I have lying around the house, but would appreciate people testing and developing more.

    Since it's in a relatively untested state I've not included an examples directory for not to dissuade people who don't know what they're doing from using the library until it's more stable.

    Library is available at: https://github.com/chrisstaite/TeensyDmx - I've adopted the same MIT license. I don't think that breaks anyone else's license that I've copied code from.

  25. #25
    this looks very interesting chris.
    do you think you could also upload an example sketch to github for dmx send, receive and RDM?

    thanks.

Posting Permissions

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