bbcmicrobit / micropython

Port of MicroPython for the BBC micro:bit
https://microbit-micropython.readthedocs.io
Other
609 stars 286 forks source link

RS232 Serial Transmit / Receive #472

Closed jemerlia closed 6 years ago

jemerlia commented 7 years ago

Transmit Issue The init() function leaves a single byte in the FIFO transmit buffer which, as expected, is transmitted first. Not an issue with some peripherals it is vexatious with such as the Honeywell PM2.5 sensor - which only accepts fixed format commands and which seems unable to recover having received junk.

However, the transmit buffer problem is easily deal with - flush with a dummy read. Thus the PM2.5 sensor additional effort (eg a relay) appears essential to delay sensor power-on activation until the micro:bit's transmitter buffer has been flushed.

Receive issue Most of the uart.receive functions appear not to work as specified - however, uart.readall() does what is required.

Question: have the uart.read.. functions been thoroughly tested, are they a work in progress - or, should I be back on the tablets? :)

On the credit side i2C and bluetooth BLE radio have been a joy to work with.

dpgeorge commented 7 years ago

The UART object should be working ok. Please can you post some minimal code that reproduces the problem, along with a description of how the code is run and the version of MicroPython (use import os; os.uname() at the REPL).

whaleygeek commented 7 years ago

Just for clarification, the radio in use with MicroPython is not Bluetooth and is not BLE. It uses a proprietary peer to peer protocol designed by Nordic that sits on top of the existing Bluetooth MAC (the hardware that provides the on-air interface). You can read about this on our tech pages at https://tech.microbit.org or search for Nordic Gazell.

On 4 October 2017 at 00:28, Damien George notifications@github.com wrote:

The UART object should be working ok. Please can you post some minimal code that reproduces the problem, along with a description of how the code is run and the version of MicroPython (use import os; os.uname() at the REPL).

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bbcmicrobit/micropython/issues/472#issuecomment-334008105, or mute the thread https://github.com/notifications/unsubscribe-auth/AD5cAbowMQfQiaTTRPX1AhDGQxoSnAmGks5sosMbgaJpZM4Ps0bw .

jemerlia commented 7 years ago

Hello Damien Thank you for your reply.  The information you requested and some discussion follows.  Suggestions gratefully received! Best wishes => Terry

===START===

os.uname() (sysname='microbit', nodename='microbit', release='1.0', version='v1.7-9-gbe020eb on 2016-04-18', machine='micro:bit with nRF51822')

INTERFACE The PM2.5 sensor is a 5v device operating at 9k6 baud but drives the RS232 lines at 0V-3.3V.  Data transfers successfully, bidirectionally once the fix shown below (Problem 2) is in place -  it appears the slightly elevated PM2.5 transmit voltage is acceptable to the micro:bit (operating at 3.125V) probably causing only a small amount of clipping. PROBLEM 1Micro:bit UART TX buffer is not clear following uart.init() Micro:bit only: TX - RX loopback test Writing a text string, or even just the empty string, "", transmits a leading 0x00. Please examine the screen output (two bytearrays) following the code.  Note the use of sleep() calls to prevent character misplacement or loss.

CODE# Loopback Microbit's TX-RX linked

Showing Microbit UART Transmit Buffer Contents

from microbit import * uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin12, rx=pin16) sleep(5) uart.write("Hello!") sleep(10) value1 = uart.readall() uart.write("No Reply!") sleep(10) value2 = uart.readall()

Back To REPL

uart.init(baudrate=115200) print(value1) print(value2) OUTPUT (Copied from REPL window) b'\x00Hello!' b'No Reply!' Note:

  1. The unwanted, leading '\x00'
  2. The potentially useful uart.readinto() executes but not that helpfully and not in the way intended!

PROBLEM 2Sensor power-up must follow microbit init() Despite the unwanted leading character transmitted by the microbit, the sensor remains unaffected, executing commands normally. However, the sensor responds adversely to the microbit's init() following its own power up - commands are not executed for reason or reasons unknown and all microbit uart read functions time out. Without an oscilloscope or logic analyser it's difficult to understand the cause - a different RS232 device (an LCD display) works correctly following a microbit uart.init() after deletion of the unwanted leading character.  It is possible the sensor is oversensitive to initial TX,RX line states - but that is pure guesswork.  Further, the Honeywell datasheet is skeletal. This problem may not be the microbit's fault but a software solution would have been useful because a hardware fix - a transistor driven SPST relay controlling the sensor power supply adds more components and increases power drain.  At the time of writing I have not tested the sensor with another system and so do not have a useful comparison.  Perhaps the next realistic step is to consult Honeywell (don't catch your breath).

Question: is there anything unusual about the initial state of the microbit's I/O pins and/or the uart.init() which could possibly affect peripheral devices?

For the sake of completeness the following single-shot code (write configuration, take one PM reading) follows: CODE

Honeywell PM2.5 Sensor Test1

from microbit import * ReadCustomerCoeff              = bytearray([0x68,0x01,0x10,0x87]) EnableAutoSend                    = bytearray([0x68,0x01,0x40,0x57]) StopAutoSend                        = bytearray([0x68,0x01,0x20,0x77]) StartParticleMeasurement      = bytearray([0x68,0x01,0x01,0x96]) ReadParticleMeasurement     = bytearray([0x68,0x01,0x04,0x93]) StopParticleMeasurement      = bytearray([0x68,0x01,0x02,0x95]) print("Accessing PM2.5 Sensor..\n")

Microbit visual indicator

display.set_pixel(0,0,9)  #Light pixel 0,0 uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin12, rx=pin16) sleep(2)

Flush microbit's UART transmit buffer - do not activate sensor until microbit display clear

uart.write("")   actually unnecessary

Power Up PM2.5 Sensor-appears to require microbit's TX, RX stable-already initialised.# Then press Button A

while not button_a.is_pressed():     pass

Turn off microbit pixel to indicate sensor access..

display.set_pixel(0,0,0)

Flush sensor transmit buffer: it initialises with a 32-byte packet - reason unknown

PM2.5 document is by no means exhaustive

junk = uart.readall() uart.write(StopAutoSend) sleep(15)     # Let internal processing complete autosendstatus = uart.readall() sleep(15) uart.write(StopParticleMeasurement) sleep(15) measurementstatus = uart.readall() sleep(15) uart.write(ReadCustomerCoeff) sleep(15) ReadStatus1 = uart.readall() sleep(15) uart.write(StartParticleMeasurement) sleep(7000)                 # Wait maximum of 6s for conversion, PM2.5 requirement ParticleMeasurementStart = uart.readall() sleep(15) uart.write(ReadParticleMeasurement) while not uart.any():   # Works OK but of limited use here..     pass sleep(15) PMCount = uart.readall() sleep(15)

Return to REPLuart.init(baudrate=115200)

print("Back to console..\n") print("Particle measurement status off..") if measurementstatus is None:     print("None") else:     for i in range(0,len(measurementstatus)):         print(hex(measurementstatus[i]), end=" ")

Etc for other items

OUTPUT  (All returned bytearrays are as expected) Accessing PM2.5 Sensor.. Back to console.. Particle measurement status off.. 0xa5 0xa5 autosend 0xa5 0xa5 Customer Coeff.. 0x40 0x2 0x10 0x64 0x4a ParticleMeausurementStart 0xa5 0xa5 PMCount 0x40 0x5 0x4 0x0 0x9 0x0 0xa 0xa4 The uart.any() function works but an immediately following sleep() is essential-presumably to allow the completion of buffering.

====END===

On Wednesday, 4 October 2017, 12:28:29 PM NZDT, Damien George <notifications@github.com> wrote:  

The UART object should be working ok. Please can you post some minimal code that reproduces the problem, along with a description of how the code is run and the version of MicroPython (use import os; os.uname() at the REPL).

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

dpgeorge commented 7 years ago

@jemerlia thanks for the detailed report. I can confirm that the UART does indeed send a 0x00 byte after uart.init() is called. It's because the underlying mbed driver transmits a dummy byte. I've now fixed it in bba236aafb02e6ae8ad250577f70f330d4f6bee7. I've also made the uart.read() functions better behaved: they now wait a little between reading character before returning. This will prevent short reads. See f9ad1f1625675d1bbd551079b78b800f13da55e2 for details.

Note thate the fixes are on the "version1" branch. A copy of the latest firmware with the above fixes can be found here: http://micropython.org/resources/firmware/microbit-micropython.hex

DavidWhaleMEF commented 6 years ago

I'm also really struggling to get the uart receive functions working with any form of reliability. The micro:bit completely locks up - no exception or anything.

Here is the version traceability:

>>> import os
>>> os.uname()
(sysname='microbit', nodename='microbit', release='1.0', version='v1.7-9-gbe020eb on 2016-04-18', machine='micro:bit with nRF51822')

Here is my code

from microbit import *

HOST_CMD_PARAM_MASK = 0x80
HOST_CMD_PAGE1      = 0x81
HOST_CMD_NO_SIGNAL  = 0xFD
HOST_CMD_FF         = 0xFE
HOST_CMD_FOLLOWS    = 0xFF

STATE_UNKNOWN = 0
STATE_CMD     = 1
STATE_PARAM   = 2
STATE_DATA    = 3

MAX_SLOTS = 25

def all_off():
    display.clear()

def write(slot, v):
    if slot is not None:
        if slot > 8 and v != 0:
            raise ValueError("DMX slot %s=%s" % (str(slot), str(v)) )
        v = int(v/28) # convert range 0..255 to 0..9
        slot -= 1 # pixels indexed from 0
        if slot >= 0 and slot < MAX_SLOTS:
            display.set_pixel(slot%5, int(slot/5), v)

def run():
    buf = bytearray(1)

    state = STATE_UNKNOWN
    slot = None
    uart.init(baudrate=38400, tx=pin0, rx=pin1)
    last_rx = running_time()

    while True:
        now = running_time()
        if not uart.any():
            if now-last_rx > 1000:
                raise ValueError("1sec uart rx timeout")
        else:
            uart.readinto(buf, 1)
            d = buf[0]
            last_rx = now

            if state == STATE_UNKNOWN:
                if d == HOST_CMD_FOLLOWS:
                    state = STATE_CMD

            elif state == STATE_CMD:
                if d == HOST_CMD_FF:
                    if slot is not None:
                        slot += 1
                        write(slot, 0xFF)
                        state = STATE_DATA
                        if slot >= MAX_SLOTS:
                            slot = None

                elif d == HOST_CMD_NO_SIGNAL:
                    all_off()
                    state = STATE_UNKNOWN
                    slot = None

                elif d == HOST_CMD_PAGE1:
                    slot = 0
                    state = STATE_DATA

                elif (d & HOST_CMD_PARAM_MASK) == 0:
                    state = STATE_PARAM

                else:
                    state = STATE_DATA

            elif state == STATE_PARAM:
                # ignore any parameter based commands, for now
                # note, will have to handle escaped FF here too
                state = STATE_DATA

            elif state == STATE_DATA:
                if d == HOST_CMD_FOLLOWS:
                    state = STATE_CMD
                else:
                    if slot is not None:
                        slot += 1
                        write(slot, d)
                        if slot >= MAX_SLOTS:
                            slot = None
                        # stay in data state

try:
    print("running DMX-display")
    run()
except Exception as e:
    display.show(Image.SAD)
    uart.init(baudrate=115200)
    print(e)
    sleep(500)
    reset()

It's worth saying that different buffer sizes have been tried and different random flickering of the LEDs occur with different buffer sizes, suggesting that the buffer is being trashed at intervals. It was more reliable with a buffer size of 1, but still randomly completely locks up with no exception and I have to reboot the micro:bit

DavidWhaleMEF commented 6 years ago

I never see the 1 sec rx timeout. I never see any exceptions. I occasionally see spurious flickering of the first few LEDs, and after a few seconds the micro:bit completely hangs and I have to press the reset button.

DavidWhaleMEF commented 6 years ago

For completeness, here is a logic analyser trace so you can see the data coming in. Data payloads are variable but usually about 34 bytes, could expand worst case up to about 66 bytes. Baud rate 38400.

screen shot 2017-12-09 at 17 53 54

DavidWhaleMEF commented 6 years ago

Also, can you confirm what the timeout time is, and what the internal uart buffer size is (i.e. number of bytes it will store before data is lost), as none of this information seems to be available in the official docs. If you could add that to the official docs at the same time, that would be really super, thanks!

DavidWhaleMEF commented 6 years ago

I have tried with 2 stop bits at the transmitting end, no change. There is 10ms of idle time between payloads of length 34 bytes when 2 stop bits are in place at 38400bps. Clearly this will be stressing MicroPython a lot, but I wouldn't expect it to completely lock up the micro:bit and require a hard reboot - that's not good, is it?!

Any clues?

jemerlia commented 6 years ago

I've had limited success receiving data (9k6baud - other parameters default) from a Honeywell PM2.5 sensor. In the past I've had at best mixed results from most of the uart receive functions and so limited my use to uart.any() and uart.readall(). Data reception is erratic at the best of times, after previous correspondence about spurious buffer characters and data loss I assumed problems had been fixed. Honeywell were most supportive and are sending me a replacement but now it may be possible the sensor was not at fault.  Having no data analyzer, etc, my investigations are limited and so I wait the response to David's issues with interest. Best wishes => Terry Morris

On Sunday, 10 December 2017, 6:51:45 AM NZDT, David Whale (Micro:bit Educational Foundation) <notifications@github.com> wrote:  

I'm also really struggling to get the uart receive functions working with any form of reliability. The micro:bit completely locks up - no exception or anything.

Here is the version traceability:

import os os.uname() (sysname='microbit', nodename='microbit', release='1.0', version='v1.7-9-gbe020eb on 2016-04-18', machine='micro:bit with nRF51822')

Here is my code from microbit import *

HOST_CMD_PARAM_MASK = 0x80 HOST_CMD_PAGE1 = 0x81 HOST_CMD_NO_SIGNAL = 0xFD HOST_CMD_FF = 0xFE HOST_CMD_FOLLOWS = 0xFF

STATE_UNKNOWN = 0 STATE_CMD = 1 STATE_PARAM = 2 STATE_DATA = 3

MAX_SLOTS = 25

def all_off(): display.clear()

def write(slot, v): if slot is not None: if slot > 8 and v != 0: raise ValueError("DMX slot %s=%s" % (str(slot), str(v)) ) v = int(v/28) # convert range 0..255 to 0..9 slot -= 1 # pixels indexed from 0 if slot >= 0 and slot < MAX_SLOTS: display.set_pixel(slot%5, int(slot/5), v)

def run(): buf = bytearray(1)

state = STATE_UNKNOWN
slot = None
uart.init(baudrate=38400, tx=pin0, rx=pin1)
last_rx = running_time()

while True:
    now = running_time()
    if not uart.any():
        if now-last_rx > 1000:
            raise ValueError("1sec uart rx timeout")
    else:
        uart.readinto(buf, 1)
        d = buf[0]
        last_rx = now

        if state == STATE_UNKNOWN:
            if d == HOST_CMD_FOLLOWS:
                state = STATE_CMD

        elif state == STATE_CMD:
            if d == HOST_CMD_FF:
                if slot is not None:
                    slot += 1
                    write(slot, 0xFF)
                    state = STATE_DATA
                    if slot >= MAX_SLOTS:
                        slot = None

            elif d == HOST_CMD_NO_SIGNAL:
                all_off()
                state = STATE_UNKNOWN
                slot = None

            elif d == HOST_CMD_PAGE1:
                slot = 0
                state = STATE_DATA

            elif (d & HOST_CMD_PARAM_MASK) == 0:
                state = STATE_PARAM

            else:
                state = STATE_DATA

        elif state == STATE_PARAM:
            # ignore any parameter based commands, for now
            # note, will have to handle escaped FF here too
            state = STATE_DATA

        elif state == STATE_DATA:
            if d == HOST_CMD_FOLLOWS:
                state = STATE_CMD
            else:
                if slot is not None:
                    slot += 1
                    write(slot, d)
                    if slot >= MAX_SLOTS:
                        slot = None
                    # stay in data state

try: print("running DMX-display") run() except Exception as e: display.show(Image.SAD) uart.init(baudrate=115200) print(e) sleep(500) reset()

It's worth saying that different buffer sizes have been tried and different random flickering of the LEDs occur with different buffer sizes, suggesting that the buffer is being trashed at intervals. It was more reliable with a buffer size of 1, but still randomly completely locks up with no exception and I have to reboot the micro:bit

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

DavidWhaleMEF commented 6 years ago

I am having similar 'uart receive locking behaviour' in MakeCode, so I wonder if this is an mbed or a DAL problem?

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

DavidWhaleMEF commented 6 years ago

Having seen a similar issue in MakeCode, I will now try to create a smaller repro case in MicroPython here (i.e. extracting the core part from my application code into a tiny example like the makecode example) to see if I can create a simple repro test case.

DavidWhaleMEF commented 6 years ago

Okay, I think these two issues are unrelated (the makecode and micropython one)

I am going on the following hunch at the moment..

I remembered something that @dpgeorge mentioned a while ago. If you receive binary data 0x03, this is a CTRL-C, which is processed by the MicroPython interpreter and stops the program from running, dumps the startup text on the tx line, then waits at a prompt.

@jemerlia are you receiving binary data from your sensor, and is it possible it could send a byte 0x03 back in it's response any time? If so, then you are bascially CTRL-C'ing (KeyboardInterrupt-ing) your program and it will stop working at that point.

@dpgeorge how do we turn off CTRL-C processing in MicroPyton on the UART so that we can process binary payloads sent back via the UART tx line?

DavidWhaleMEF commented 6 years ago

There is some generic MicroPython chatter here about the CTRL-C problem, that may be relevant...

https://forum.micropython.org/viewtopic.php?t=2848

DavidWhaleMEF commented 6 years ago

So, my test above was done (for expediency) using USBSER, not redirected UART.

This issue suggests that CTRL-C is disabled when the uart is redirected, although I'm not sure that is the case, I will try it with my external hardware board.

https://github.com/micropython/micropython/issues/1568

DavidWhaleMEF commented 6 years ago

This was the minimal test I was doing, however I was sending a text file and a binary file from my serial terminal. Of course the binary file has 0x03's in it and stops the REPL, so it was a bit of a duff test really.

from microbit import *

buf = bytearray(1)
display.show(Image.HEART)

while True:
    if uart.any():
        uart.readinto(buf, 1)
        d = buf[0]
        d = int(d/28)
        display.show(str(d))
        #sleep(20)
    if button_a.was_pressed():
        display.show(Image.HEART)

I'll see if I can get my external hardware to generate an 0x03 to prove whether the CTRL-C is active or transparent when redirected. There's nothing about this in the docs, and I can't really get to the bottom of how it is configured by reading through the issues on github.

ntoll commented 6 years ago

@DavidWhaleMEF you're aware that UART can go into "raw" mode..? Could this be something to fix your problem. See, for example, the raw_on and raw_off functions in microfs (start here: https://github.com/ntoll/microfs/blob/master/microfs.py#L55)... or is this perhaps trying to perform the same sort of operation but from code running on the actual device (rather than from a program connecting via UART). Hope this helps.

DavidWhaleMEF commented 6 years ago

Thanks @ntoll yes I use the RAW repl in bitio.

However I'm not using the REPL. I am attached to a device on the pins which sends binary data to a running MicroPython script, and it is locking the micro:bit completely in yet undetermined circumstances. I was clutching at straws with the 0x03, there is some reference form @dpgeorge to the Ctrl_C handling being disabled when the UART is redirected, but I haven't completely confirmed this yet.

DavidWhaleMEF commented 6 years ago

DAPLink Firmware - see https://mbed.com/daplink Version: 0234 Build: Oct 12 2015 14:39:34

DavidWhaleMEF commented 6 years ago

As suggested by @jaustin Just updated to latest firmware from here, will try again

https://support.microbit.org/support/solutions/articles/19000019131-how-to-upgrade-the-firmware-on-the-micro-bit

DAPLink Firmware - see https://mbed.com/daplink

Unique ID: 9900000032044e4500158016000000650000000097969901 HIC ID: 97969901 Auto Reset: 1 Automation allowed: 0 Overflow detection: 0 Daplink Mode: Interface Interface Version: 0243 Git SHA: b403a07e3696cee1e116d44cbdd64446e056ce38 Local Mods: 0 USB Interfaces: MSD, CDC, HID Interface CRC: 0x14256f44 Remount count: 0

DavidWhaleMEF commented 6 years ago

Still crashes with latest firmware version @jaustin

DavidWhaleMEF commented 6 years ago

Okay @dpgeorge @ntoll @jaustin @jemerlia I have confirmed as below, that when an 0x03 is received via the UART when redirected to the pins (i.e. receiving binary data from an external device), a KeyboardInterrupt is generated.

Here is the code...

from microbit import *

def run():
    uart.init(baudrate=38400, tx=pin0, rx=pin1)
    buf = bytearray(1)
    display.show(Image.HEART)

    while True:
        if uart.any():
            uart.readinto(buf, 1)
            d = buf[0]
            d = int(d/28)
            display.show(str(d))
        if button_a.was_pressed():
            display.show(Image.HEART)

try:
    print("starting tester")
    run()
except Exception as e:
    uart.init(baudrate=115200)
    display.show(Image.SAD)
    print(e)
    sleep(1000)
    reset()
except KeyboardInterrupt:
    uart.init(115200)
    print("Keyboard int")
    sleep(1000)
    reset()

Here is what I send in on the pin

screen shot 2017-12-10 at 13 59 56

Here is what I see on the REPL (note I redirect back to the USBSER to get error messages out)

starting tester
Keyboard int
starting tester
Keyboard int
starting tester
Keyboard int
starting tester
Keyboard int
starting tester
Keyboard int
ntoll commented 6 years ago

Sure, I (think I) understand what you're doing. My point was to check if you might be able to do an equivalent "raw mode"-ish change for non-REPL uart usage. I'm not sure I know enough to make any helpful contributions, so I guess @dpgeorge will be able to shine more light onto this.

Seasons' greetings! :santa: :mrs_claus: :christmas_tree: :snowman:

jemerlia commented 6 years ago

The sensor might well return 0x03 - it's legitimate data and a possible checksum component - and it would apparently appear at random, because it is dependent upon environmental conditions which could change at any time..

On Monday, 11 December 2017, 1:24:31 AM NZDT, David Whale (Micro:bit Educational Foundation) <notifications@github.com> wrote:  

Okay, I think these two issues are unrelated (the makecode and micropython one)

I am going on the following hunch at the moment..

I remembered something that @dpgeorge mentioned a while ago. If you receive binary data 0x03, this is a CTRL-C, which is processed by the MicroPython interpreter and stops the program from running, dumps the startup text on the tx line, then waits at a prompt.

@jemerlia are you receiving binary data from your sensor, and is it possible it could send a byte 0x03 back in it's response any time? If so, then you are bascially CTRL-C'ing (KeyboardInterrupt-ing) your program and it will stop working at that point.

@dpgeorge how do we turn off CTRL-C processing in MicroPyton on the UART so that we can process binary payloads sent back via the UART tx line?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

jemerlia commented 6 years ago

The PM25 sensor communicates sensibly and bidirectionally with TeraTerm.  The 0x03 problem would certainly explain the unpredictable Micro:bit RS232 reads.

On Monday, 11 December 2017, 3:01:01 AM NZDT, David Whale (Micro:bit Educational Foundation) <notifications@github.com> wrote:  

Okay @dpgeorge @ntoll @jaustin @jemerlia I have confirmed as below, that when an 0x03 is received via the UART when redirected to the pins (i.e. receiving binary data from an external device), a KeyboardInterrupt is generated.

Here is the code... from microbit import *

def run(): uart.init(baudrate=38400, tx=pin0, rx=pin1) buf = bytearray(1) display.show(Image.HEART)

while True:
    if uart.any():
        uart.readinto(buf, 1)
        d = buf[0]
        d = int(d/28)
        display.show(str(d))
    if button_a.was_pressed():
        display.show(Image.HEART)

try: print("starting tester") run() except Exception as e: uart.init(baudrate=115200) display.show(Image.SAD) print(e) sleep(1000) reset() except KeyboardInterrupt: uart.init(115200) print("Keyboard int") sleep(1000) reset()

Here is what I send in on the pin

Here is what I see on the REPL (note I redirect back to the USBSER to get error messages out) starting tester Keyboard int starting tester �Keyboard int starting tester �Keyboard int starting tester �Keyboard int starting tester �Keyboard int

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

dpgeorge commented 6 years ago

@DavidWhaleMEF please try using the "version1" branch (if you didn't already) because it has lots of fixes and updates. In particular it has micropython.kbd_intr(chr) and if you pass -1 as the chr argument then that will disable ctrl-C interrupts.

The problems with UART may be related to the mbed UART driver because that is known to have issues ever since the beginning, see #107 (also #45 may be relevant). @jaustin is aware of this issue (maybe it's been fixed by now?).

DavidWhaleMEF commented 6 years ago

Thanks. Is there a target release date for version 1, this is for a project that will surface in the public and must work with whatever the current released versions of python.microbit.org and codewith.mu are using. Thanks!

dpgeorge commented 6 years ago

Is there a target release date for version 1

There is no plan for the release. When is your project going live?

DavidWhaleMEF commented 6 years ago

This particular one is currently due to be shown to a public audience early March, with them expecting to download and run the code themselves soon after that.

dpgeorge commented 6 years ago

This particular one is currently due to be shown to a public audience early March,

Ok, version1 should definitely be out by then :)

DavidWhaleMEF commented 6 years ago

@dpgeorge is it possible that the .hex URL you published in this comment: https://github.com/bbcmicrobit/micropython/issues/472#issuecomment-334364423 could be serialised in some way with the version and build increment or something? Problem is we have no traceability over that at the moment, so if we direct users to 'have you tried the latest version 1 release candidate' we never really know if they are using the correct one (or which one they used). It's just going to get us in a pickle if people test with untraceable .hex files. Thanks!

jemerlia commented 6 years ago

It may be useful to leave a prominent warning note for general users that RS232 input should be avoided until the release of a robust firmware update.  Although I will not discuss the matter in this thread I hope I will be permitted the observation that MakeCode (Javascript) gave a similar experience with RS232 input, compounded by missing methods etc.  I also support the suggestion of others for firmware update automation; the current procedure is too complex for many users.

Best wishes =>Terry

On Thursday, 14 December 2017, 1:36:17 AM NZDT, David Whale (Micro:bit Educational Foundation) <notifications@github.com> wrote:  

@dpgeorge is it possible that the .hex URL you published in this comment: #472 (comment) could be serialised in some way with the version and build increment or something? Problem is we have no traceability over that at the moment, so if we direct users to 'have you tried the latest version 1 release candidate' we never really know if they are using the correct one (or which one they used). It's just going to get us in a pickle if people test with untraceable .hex files. Thanks!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

dpgeorge commented 6 years ago

@DavidWhaleMEF I had a look at your DMX code from comment https://github.com/bbcmicrobit/micropython/issues/472#issuecomment-350493724 . Put simply: I think that MicroPython is not able to process fast enough payloads of 34 bytes with 10ms separation.

I ran some of my own tests both sending and receiving data with the microbit uart. Sending data out of the microbit is no problem, you can go as fast as you like.

Receiving data can lead to issues. First, you need to issue micropython.kbd_intr(-1) before doing uart.init(...) to disable ctrl-C. Second, the rate of data coming int to the microbit uart must be slow enough for your code to handle it.

I found that with a payload of 34 bytes and baudrate of 38400, and with the microbit processing one incoming character at a time, the minimum time between payloads is about 13ms. But this was with very simple character processing code. For more complex code it would take longer and hence need more time between payloads.

For reference my test code is, on the microbit:

import micropython
import microbit

micropython.kbd_intr(-1)
ua = microbit.uart
ua.init(tx=microbit.pin0, rx=microbit.pin1, baudrate=38400)

buf = bytearray(1)
last_c = 0 
n_bad = 0 
while 1:
    if ua.any():
        ua.readinto(buf)
        c = buf[0]
        if c != (last_c + 1) & 0xff:
            n_bad += 1
            microbit.display.show('%u' % n_bad)
        else:
            microbit.display.set_pixel(0, 0, c % 10) 
        last_c = c 

and on a pyboard with X1->pin1, Y2->pin0:

import time
import pyb 
ua = pyb.UART('XA', 38400, timeout=0)

i = 0 
while 1:
    if i == 0:
        print('still writing...')
    buf = bytearray(34)
    for j in range(len(buf)):
        buf[j] = i + j 
    ua.write(buf)
    i = (i + len(buf)) & 0xff
    time.sleep_ms(13)

In summary: I did not find any bugs in the uart code (on version1 branch at e17de0954178d88aa2a1d70b6e6ebc43f5456607).

dpgeorge commented 6 years ago

what the internal uart buffer size is (i.e. number of bytes it will store before data is lost)

It's hard coded to 64 bytes.

DavidWhaleMEF commented 6 years ago

Thanks @dpgeorge this is very helpful indeed.

Would it be possible to update the docs to say that the buffer is hard coded at 64 bytes?

Also, detecting corruption due to buffer overflow is really hard with the current scheme, unless CRC's are added to the application payload, which might not always be possible at the sending end.

I was wondering, Is there any opportunity to add something that sets a flag when the UART interrupt tries to write to the 64 byte buffer and there is no more space and junks a byte, and a uart.was_overflow() method that reads and clears the flag? That way, application code would at least have a chance to detect data loss and junk that data and get round to re-syncing and processing the next payload quickly? Just a thought.

Thanks for your analysis and testing, very helpful.

microbit-carlos commented 6 years ago

Looks like the original issue has been fixed (garbage byte sent on uart init).

The conversation then diverted into a different issue with the uart module, which I believe has concluded with a request to update the documentation and a feature request.

To keep things a bit organised I will label and close this issue, and have created these other two:

Please feel free to reopen if something is not yet fixed, or if a further discussion outside those two issues is needed.