philipphenkel / pxt-powerfunctions

MakeCode extension for controlling your LEGO Power Functions devices with an IR-emitting LED
https://www.hackster.io/philipp-henkel/lego-power-functions-ir-sender-for-micro-bit-aecc10
MIT License
49 stars 11 forks source link

Possibly brittle timing #1

Closed DavidWhaleMEF closed 7 years ago

DavidWhaleMEF commented 7 years ago

This code leaves itself open to being possibly brittle in its timing (especially with upgrades to the MakeCode runtime and interference from interrupts).

            // calliope correction -85, -210
            // microbit correction -65, -150
            transmitBit(markMicroSeconds: number, pauseMicroSeconds: number): void {
                pins.analogWritePin(this.pin, 511)
                control.waitMicros(Math.max(1, markMicroSeconds - 65))
                pins.analogWritePin(this.pin, 0)
                control.waitMicros(Math.max(1, pauseMicroSeconds - 150))

There is a new feature added to MakeCode beta that should make it possible implement bit-banging solutions like this to be more resilient in these cases...

https://github.com/Microsoft/pxt/issues/3198

Calculate a forward looking time horizon, then wait until the microsecond timer has achieved that value. Variances in timing due to different execution speeds on different versions of the runtime, or interference from interrupts should then be minimised.

DavidWhaleMEF commented 7 years ago

It turns out on further investigation, that control.WaitMicros finds it's way down to the mbed classic wait_us/ platform specific us_ticker_read, so depending on how that is implemented, this might be ok after all.

philipphenkel commented 5 years ago

@DavidWhaleMEF While I was using the high precision timer, the code was still heavily depending on the implementation of analogWritePin (it uses floats internally!!!) and waitMicros.

Recently, I changed my approach. Now, I measure the runtime of those functions when initializing the code. This way my library works even if the MakeCode stacks is updated (pxt / DAL / mbed).

public transmitBit(markMicroSeconds: number, pauseMicroSeconds: number): void {
      pins.analogWritePin(this.pin, 511)
      control.waitMicros(markMicroSeconds - this.writeAndWaitEffort)
      pins.analogWritePin(this.pin, 0)
      control.waitMicros(Math.max(1, pauseMicroSeconds - this.writeAndWaitEffort - this.messageProcessingEffort))
}