Avatar for CamSwords

CamSwords

Member since Mar 2014 • Last active Jun 2014
  • 1 conversations
  • 6 comments

Most recent activity

    • 13 comments
    • 8,519 views
  • in General
    Avatar for CamSwords

    Cheers Gordon,

    You're right, 640ms waiting for a quad would be disastrous! Needless to say, our quad isn't flying just yet.

    I didn't realise that serial output ended up on the same IO Event queue, but that makes more sense as to why the queue was full. Is the waiting for space in the queue that occurs the following loop in jsdevices.c? If so does that work because there is an interrupt consuming characters from the queue and sending them over the wire?

    while (txHeadNext==txTail) {
      // wait for send to finish as buffer is about to overflow
    }
    

    By the way, the equation you gave was 20*32 = 640ms. Does that imply that the maximum io event queue size is 32 on an Espruino?

    I'll try all of the suggestions you made, thanks. I'm a little scared because we have two I2C devices to attach on top of what we have there now. I think we'll get it flying, though I expect it to be a little clunky and unresponsive.

    Cheers for your help!
    Cam

  • in General
    Avatar for CamSwords

    Maybe! Although from what I can tell the queue size will be 64 events long on an Espruino (32 events long on a board with less flash). IO Events are any work that needs to be done regarding external line interrupts (setWatch), serial (usb and via pins), SPI and I2C. For example, each character received on a Serial read is one IO Event.

    In my use case, my input pin was receiving pulses every 20ms. I got a reading of time between events (event.time - event.lastTime) of 0.053564071 seconds, in which I expect 4 - 6 IO Events to occur due to my pin edge rising / falling. For me to fill the queue I think I would have had to have other events on it too, presumably incoming characters on a serial link, though I'm a bit sceptical now because I thought that my Espruino serial link was only sending characters out.

    One thing I might try is not making my setWatch repeat, just turning it on every now and again might mean less events in the queue for me.

  • in General
    Avatar for CamSwords

    Ok, I think I understand my PWM input woes now.

    An external interrupt is registered on the rising and falling edge of a pin. The interrupt code records the pin, time, and pin state and pushes an io-event to an event queue. Later, in the main program loop (in jsidle) the io-events are consumed. Here, depending on whether the user specified rising, falling or both, and the state of the pin then one of two things will happen. If the callback shouldn't be triggered (eg. falling edge when the user watches for rising edges) then the lastTime will be set to the event time and the loop will continue. If it's callback time, then the previously defined lastTime will be used along with the event time and the callback will be executed.

    The issue I'm facing is that the (event.time - event.lastTime) I'm getting is far larger than the pulse coming on the pin I'm watching. I believe this is happening because when io-events are added to the event queue they are discarded if the queue is full. That makes sense from a memory conservation point of view, however it means that "lastTime" represents the time between the current io-event and last io-event that wasn't discarded due to a full queue. That makes me distrust "lastTime" completely. I still trust "time", because it's defined when the interrupt is called, not in the main program loop.

    I think I have a work around, which is to watch the pin on both edge rising and fall and calculate the time difference using only "time". When io-events are discarded from the event queue I will still get an incorrect value, but I can recognise this because I know the minimum and maximum value that duty cycle should be on for (1ms - 2ms). Anything outside this range means that io-events were discarded and therefore I didn't get a correct reading. This means that I will get less PWM input readings, but it does mean that they will be accurate (so I believe).

    Anyone have any thoughts?

  • in General
    Avatar for CamSwords

    Cheers, @DrAzzy, I'll update the firmware. I knew about the timer sharing, though I haven't really looked in to it / understood it yet.

    I did some testing with analogWrite on my digital logic analyser. The timer does have a consistent pulse even when updating the duty cycle more frequently than the pulse width milliseconds. For example, running the code:

    var value = 0.1;
    
    setInterval(function() {
           if (value === 0.1) {
               value = 0.05;
           } else {
               value = 0.1;
           }
           analogWrite(C6, value, { freq: 50 });
    }, 10);
    

    resulted in a consistent pulse width of 20ms, and a consistent duty cycle of 2ms. I assume this takes the most recent duty cycle value when it writes the pulse, therefore it always used the "0.1" value and the "0.05" was never used as the duty cycle. Happiness! At least I've isolated my problem now.

  • in General
    Avatar for CamSwords

    Cheers for the responses!

    Gordon,

    I initially tried analogWrite, though when we started getting sporadic increases of throttle at the propeller side I thought that maybe the timer might be initialising again, in which I mean starting the pulse again as opposed to just adjusting the duty cycle. Is this the case? If I call analogWrite many times per second would you expect a consistent pulse on the output?

    Regarding the input, yes it is possible that we're sending too much out on the serial. Generally though, this means that as we add more work to do for the Espruino, the event times we read while watching will get less and less reliable. I'll read the STM docs and see if I can find anyway I can do it with peek / poke.

    Cheers
    Cam

  • in General
    Avatar for CamSwords

    Hi Gordon!

    A few of the folks at work have been building a quadcopter flight controller with me using an Espruino. It's fantastic, we've had lots of fun. We've done some interesting things - we've written a gulp deploy tool, we run unit tests using the espruino process on our macs, we have written our own AMD loader, AMD optimiser and a promise library. All of this is very crude.

    Anyone wanting to see the code can do so here:

    https://github.com/camswords/quadcopter/tree/master/src/main

    We have wired up an input pin to receive a PWM signal from the RC receiver. We have registered a function similar to the following to 'watch' on a falling edge in a repeating way.

    function(event) {
          var dutyCycle = Math.floor((event.time - event.lastTime) * 1000000);
      
          ...
    }
    

    Strangely, when we send the (dutyCycle, event.time, event.lastTime) to my laptop via bluetooth we get output such as the following (forget the strange characters, that is related to my serial / bluetooth solution, not this issue):

    981.33087158203125, 4.910�20849609375, 4.90931987762451171875|
    981.33087158203125, 4.9816s751708984375, 4.98071384429931640625|
    980.377197265625, 5.05308�71484375, 5.052104949951171875|
    981.33087158203125, 5.124489784072265625, 5.123508453369140625|
    981.33087158203125, 5.1780481338506484375, 5.24847507476806640625|
    981.33087158203125, 5.3208665847740625, 5.39130115509033203125|
    53564.0716552734375, 5.445846557�1875, 5.3922824859619140625|
    

    We expect values roughly between 1000 and 2000, as it is recording the length of the duty cycle (1ms to 2ms). Every now and again we get very large values in the time difference. My naiive guess is that this time is calculated by the CPU, not a timer? And code being executed may cause a delay between "event.time" and "event.lastTime"? If that is the case, is there anything I can do to get a timer to populate a register with the duty cycle, and have my 'watch' event fire on change of this value instead?

    I felt the same when writing PWM outputs for each of the propeller motors. We are using digitalPulse with a setInterval every 20ms, but I fear that the PWM signal quality will degrade when other code is executing at the time the signal should be pulsed. Looking at the STM library source (disclaimer: I know very little about this, and microcontrollers in general) my understanding is that I could write to a register and have a timer automatically adjust the duty cycle. I believe there is a TIM_SetCompareX method that does this.

    Does this make any sense? I'd love to hear your feedback. I'm not expecting you to solve these problems for me, I'm happy to jump into the code and send you a patch if it makes sense.

    fyi, we've been reading PWM signals on pin A8 and and sending PWM signals on pins C6, C7, C8 and C9. All of this is done on Espruino running 1v61. I'm happy to run this on a more up-to-date version of Espruino if required.

    Cheers
    Cam

Actions