Giter VIP home page Giter VIP logo

codal-microbit-v2's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

codal-microbit-v2's Issues

Getting error code 090 on new microbit

I am using SPI functions for writing to SD card with new microbit and getting error code 090 on microbit screen every time after writing two lines to SD card as if its is periodic, writes two lines shows error code 090 and restarts again.

Feature request: Sound recording API

The micro:bit microphone can detect changes in sound levels and there have been various discussions and references to how sound recording could be implemented eg microsoft/pxt-microbit#3423 (comment) and prior to V2 release in https://github.com/microbit-foundation/api-prototypes (private repo).

There are also privacy concerns around recording sound that need to be factored in.

This ticket is a public reference point to discuss the implementation of sound recording

Some refactoring of SoundExpressions

Suggestion to the current implementation:

  • use a binary format that can be mapped to a C struct
  • removing all parsing code, use of ManagedString
  • convert existing sounds to binary format

Once this is done, we can lift the sound definitions to MakeCode resources so that the simulator can eventually play them.

UIPM: RECEIVED UNKNWON FRAME?

The power manager sends DMESG("UIPM: RECEIVED UNKNWON FRAME") during the BLE DFU reboot.

This also occurs after uBit.accelerometer.setPeriod(0), sets the LSM303 ODR to 0x80 = Low-power mode (1.620 kHz).

display readLightLevel always returns 0

This example programme always reads 0:

#include "MicroBit.h"

MicroBit uBit;

int main() {
    while (1) {
        uBit.serial.send(ManagedString(uBit.display.readLightLevel()) + "\r\n");
        uBit.sleep(250);
    }
}

Power Management: When board is USB powered it cannot detect if a battery is connected as well

From the DAPLink testing:

  • The power state is not capturing all the state changes.
    • The initial power source is always well identified (USB or battery)
    • But moving from power sources isn't always detected

DAPLink is not able to differentiate battery power when USB is present, so the CODAL call is returning the "wrong" values. We'll have to update CODAL to acknowledge that the USB present masks battery being present or not.

We think/recall that the situation is as follows but @gerargz can you please confirm it's like this?

typedef enum {
    PWR_SOURCE_NONE = 0,
    PWR_USB_ONLY,    // --> will never happen/deprecated
    PWR_BATT_ONLY,   // --> Real, battery only
    PWR_USB_AND_BATT // --> Any time USB is present.
}

I'll need to add a note to https://github.com/microbit-foundation/spec-i2c-protocol/blob/main/spec/index.md#properties

i2c.write hangs with a NULL buffer

micropython has a function i2c.scan, which hangs V2 when an external i2c device is connected.

As far as I understand the micropython source, this is implemented by writing a NULL buffer to each address.

Have I got it right @dpgeorge ? I'm puzzled because my sample doesn't detect devices on a V1, whereas i2c.scan does, so I must be doing something wrong!

V2 i2c.write hangs when it gets to an attached i2c device - maybe stuck in waitForStop.

With the sample below, Press A to write to each address; B to read from each address.

#include "MicroBit.h"

#ifdef CODAL_CONFIG_H
#define MICROBIT_CODAL 1
#else
#define MICROBIT_CODAL 0
#endif


MicroBit uBit;


void i2c_scan_write()
{
    for (int addr = 0x08; addr < 0x78; ++addr)
    {
        int ret = uBit.i2c.write( addr << 1, NULL, 0, false);

        uBit.serial.printf( "write addr %x = %d\n", addr << 1, ret);
    }
}



void i2c_scan_read()
{
#if MICROBIT_CODAL
    uint8_t data[100];
#else
    char data[100];
#endif

    for ( int addr = 0x08; addr < 0x78; addr++)
    {
        memset( data, 255, 100);
        int ret = uBit.i2c.read( addr << 1, data, 1, false);
        uBit.serial.printf( "read addr %x = %d data[0] = %d\n", addr << 1, ret, (int) data[0]);
    }
}


void onButtonA(MicroBitEvent e)
{
  i2c_scan_write();
}


void onButtonB(MicroBitEvent e)
{
  i2c_scan_read();
}


void togglePixel( int x, int y)
{
    uBit.display.image.setPixelValue( x, y, uBit.display.image.getPixelValue( x, y) ? 0 : 255);
}


void forever()
{
    while (true)
    {
      togglePixel( 0, 0);
      uBit.sleep(1000);
    }
}


int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    create_fiber( forever);

    uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB);

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

serial.redirect breaks serial.

From microbit-foundation/micropython-microbit-v2#29 (comment):

#include "MicroBit.h"

MicroBit uBit;

int  main() {
    uBit.init();

    for (int i = 0; i < 10; ++i) {
        char x = uBit.serial.read();
        uBit.serial.sendChar(x);
    }

    uBit.serial.setBaud(115200);
    uBit.serial.redirect(uBit.io.usbTx, uBit.io.usbRx);

    while (1) {
        char x = uBit.serial.read();
        uBit.serial.sendChar(x);
    }
}

In the above test, the first 10 chars are echoed back correctly, but then when it redirects (to the same pins) following chars are not.

I2C read issues in MakeCode/CODAL without a repeat start

This simple MakeCode I2C write-read transaction, extracted from the Gigglebot extension, works correctly in v1 (in my device it reads "5"), but returns "0" on v2:

enum gigglebotI2CCommands {
  GET_FIRMWARE_VERSION = 1,
  GET_MANUFACTURER,
  GET_BOARD,
  GET_VOLTAGE_BATTERY,
  GET_LINE_SENSORS,
  GET_LIGHT_SENSORS,
  GET_MOTOR_STATUS_RIGHT,
  GET_MOTOR_STATUS_LEFT,
  SET_MOTOR_POWER,
  SET_MOTOR_POWERS
}
let ADDR = 0x04

function firmwareVersion(): number {
    let buf = pins.createBuffer(1)
    buf.setNumber(NumberFormat.UInt8BE, 0, gigglebotI2CCommands.GET_FIRMWARE_VERSION)
    pins.i2cWriteBuffer(ADDR, buf)
    let val = pins.i2cReadBuffer(ADDR, 2)
    basic.showNumber(val.getNumber(NumberFormat.Int8BE,0))
    basic.showIcon(IconNames.Heart)
    basic.showNumber(val.getNumber(NumberFormat.Int8LE,0))
    basic.showIcon(IconNames.Heart)
    return val.getNumber(NumberFormat.UInt16BE, 0);
}

basic.pause(1000)
basic.showNumber(firmwareVersion())

On a v1 we can clearly see the write/read:
image

Looking at the clock signal there are two transaction:

  1. Write 1 byte (2 byes)
    1. 0x8 (Address 0x4 write)
    2. 0x1 (command to read firmware version)
  2. Read 2 bytes (3 bytes in total)
    1. 0x9 (Address 0x4 read)
    2. 0x0 (MSB)
    3. 0x5 (LSB)

With the v2 connected we can see the second part is not complete :

  1. Write 1 byte (2 byes total)
    1. 0x8 (Address 0x4 write)
    2. 0x1 (command to read firmware version)
  2. Read 2 bytes (3 bytes in total)
    1. 0x9 (Address 0x4 read)
    • Transmission ends

Looks like the I2C device is sending a NACK to the read command (not pulling down the 9th bit)?
Not sure, will need to look at I2C spec.

image

This DAL/CODAL programme works on both v1 and v2:

#include "MicroBit.h"

MicroBit uBit;

enum gigglebotI2CCommands {
  GET_FIRMWARE_VERSION = 1,
  GET_MANUFACTURER,
  GET_BOARD,
  GET_VOLTAGE_BATTERY,
  GET_LINE_SENSORS,
  GET_LIGHT_SENSORS,
  GET_MOTOR_STATUS_RIGHT,
  GET_MOTOR_STATUS_LEFT,
  SET_MOTOR_POWER,
  SET_MOTOR_POWERS
};

static const uint16_t ADDR = 0x04 << 1;

int firmwareVersion() {
    int result;

    uint8_t command = GET_FIRMWARE_VERSION;
    result = uBit.i2c.write(ADDR, &command, 1, true);
    if (result != MICROBIT_OK) {
        uBit.display.print(result);
        return -1;
    }

    uint8_t buffer[2] = {0xFF, 0xFF};
    result = uBit.i2c.read(ADDR, buffer, 2);
    if (result != MICROBIT_OK) {
        uBit.display.print(result);
        return -2;
    }
    return buffer[1] | (buffer[0] << 8);
}

int main() {
    int v = firmwareVersion();

    while(1) {
        uBit.display.print(v);
        uBit.sleep(1000);
        uBit.display.clear();
        uBit.sleep(1000);
    }
}

But changing the repeat start from true to false breaks the programme in v2 with CODAL, but not in v1 with DAL.

I haven't checked the MakeCode source code in depth, but it looks like it is not sending the repeat start unless explicitly requested:
https://github.com/microsoft/pxt-microbit/blob/c3782db37081e36f211ef0637cc05e691071c773/libs/core/pins.cpp#L464

CODAL with repeat-start:
image

CODAL without repeat-start:
image

DAL without repeat-start:

image

Tested in MakeCode:
makecode.microbit.org version: 3.1.20
Microsoft MakeCode version: 6.6.3
microbit runtime version: v2.2.0-rc6

CODAL versions from today:

  • samples: 2c38d7458e5f4265451af5e6317582494bc18515
  • codal-microbit-v2: a4f0d11

With micro:bits:

  • v1.3
  • v2 RC1

Basic Neopixel driver based on PWM

We still need to add a PWM-based component to drive NeoPixels.

This is important to enable support in MicroPython (and ideally for MakeCode to use the same driver?).

MakeCode extension compatibility

Software running on a new micro:bit uses CODAL (micro:bit V1 uses the DAL) and as a result no longer includes the mbed platform. The whole microbit-DAL API is implemented in CODAL as a compatibility layer so the same code can compile and run on any micro:bit, irrespective of hardware version.

Extensions that do not compile for V2 will still be available for V1 boards, but will be disabled in V2 builds. Users will see a runtime error on the micro:bit V2 (929)

To ease the transistion away from mbed, we have also implemented the most common mbed classes in the compat layers of CODAL. These should work in most use cases, but there may be a few edge cases where the behaviour is not identical - please file CODAL bugs if you encounter this. Extensions are encouraged to move to the DAL/CODAL model, using the uBit object to ensure compatibility with all hardware.

In the future, all extensions should target the common microbit-dal API. We will not approve new extensions that use the mbed compatibility layer.

The mbed classes implemented are DigitalIn, DigitalOut, InterruptIn, Timer, Ticker, Timeout, PwmOut and can be found here.

Problems with compilation break down into roughly three categories:

1. Use of mbed APIs that are in the compatibility layer, but no inclusion of mbed.h

The following mbed classes are implemented in the compatibility layer:
PwmOut, InterruptIn, DigitalIn, DigitalOut, Ticker, Timer

If you rely on any of these classes you now need to explicitly include mbed.h (whereas previousy microbit.h or pxt.h would implicitly include that). For many extensions, just including mbed.h will resolve outstanding compilation failures.

2. Use of mbed APIs that are not included in the compatibility layer, or microbit-dal APIs that need different constructors

If you use any other part of mbed than those listed above, the quickest option is to move to the CODAL APIs right away, either using #ifdef mbcodal to make V2 specific code, or using the microbit-dal API that is common to V1 and V2.

There are some parts of the compatibility layer that we are considering extending to; but these are still WIP - if your extension requires these and this will also reslove future compatibility issues, please respond on this ticket.

  • MicroBitI2C / NRF52I2C
  • MicroBitSerial
  • MicroBitFont

3. Use of the mbed Bluetooth APIs

Going forward the extension approval process will require extensions to not use mbed.

Bluetooth all services sample hex - magnetometer service not working

There's a link to a hex file which implements "all Bluetooth services" on this page: https://tech.microbit.org/latest-revision/

The magnetometer services does not work (no compass bearing data is transmitted when notifications are enabled). I think I wrote this sample originally and my guess is that it was not updated when work was done way back to change the accelerometer used and some of the rules for using it. Originally, use of the magnetometer service automatically triggered the calibration service. That's no longer the case afaik and so this sample needs to be changed to make an explicit call to calibrate the magnetometer or something else, equally cunning.

FYI @microbit-mark

Button long press rarely indicated in Bluetooth notifications

The Bluetooth LE button service has two characteristics, one representing the state of button A and the other, Button B. A value of 0 means not pressed, 1 means pressed and 2 means "long press".

See https://lancaster-university.github.io/microbit-docs/resources/bluetooth/bluetooth_profile.html

The way long press works on micro:bit V1, you press a button and this generates a notification with value==1 and keep holding for at least 2 seconds and this causes a second notification to be sent, this time with a value of 2.

In around 20 tests, I only saw a value of 2 (long press) transmitted in the button's characteristic value notification once. The other times, despite holding the button down for over 2 seconds, I only ever saw a single notification, with a value of 1.

@microbit-mark FYI

This code used for testing: https://github.com/bittysoftware/bitty_blue_device_code/blob/master/microbit/makecode/animal_magic/bitty_blue_animal_magic.js

pulseIn implemented with CODAL

The current pulseIn is not precise as it is based on pulling the pin sensor. Is it possible to implement "pulse" feature using CODAL pin events? Used for sonars and such.

Difference in note/melody behaviour between DAL and CODAL

In DAL notes of the same pitch and length had some definition or slight pause between the notes played, so you could distinguish by ear that the same pitch was being played twice. In CODAL this is no longer the case.

Using a pre-built melody such as Ode To Joy demonstrates this.

image

  1. Flash this program from https://makecode.microbit.org/#editor
  2. Flash this program from https://makecode.microbit.org/v2/#editor

You will hear the audible difference.

This also reproduces in MicroPython 2.0.0-beta.1 vs MicroPython 1.0.1

Bluetooth IO Pin Service not allowing control of pin connected devices

The Pin Data characteristic belonging to the IO Pin Service allows the state of micro:bit pins to be changed, by writing to the characteristic value. How the data is interpreted depends on the value of other configuration characteristics in the same service. In the simplest case, Pin Data acts as a series of binary pin number/value pairs.

Writing a value of 0x000101000200 to this characteristic should switch pin 0 on, pin 1 off and pin 2 off. Doing this using the nRF Connect application against a V1 micro:bit, with an LED connected to pin 0, works as expected. The LED switches on. Performing the same test on a micro:bit V2 does not work.

Use this code for testing: https://github.com/bittysoftware/bitty_controller_device_code/blob/master/microbit/makecode/switches.js

FYI @microbit-mark

Buttons A and B fire HOLD events only once per button. AB events do not always show if A or B listener is registered

The code below seems to work as expected on V1, though I'm not sure exactly how it should work.

V2 sees HOLD events only once per button.

If an AB listener is also registered (commented out below), V2 also sees LONG_CLICK events only once per button, and doesn't see any AB events.

If only an AB listener is registered, V2 sees AB events but HOLD and LONG_CLICK fire only once.

If AB is registered with one of A or B, AB events depend on the order A and B are pressed and released. This is the case on V1 and V2, but the exact behaviours are different: AB up or down missing; or AB click missing.

If all three listeners are registered V1 sees HOLD events for A and B, but not AB.

// This tests button events
// See serial output in a terminal program 

#include "MicroBit.h"

MicroBit uBit;


void onButtonEvent(MicroBitEvent e)
{
  ManagedString btnName;
  ManagedString btnEvent;

  switch ( e.source)
  {
    case MICROBIT_ID_BUTTON_A:  btnName = "A "; break;
    case MICROBIT_ID_BUTTON_B:  btnName = " B"; break;
    case MICROBIT_ID_BUTTON_AB: btnName = "AB"; break;
  }

  switch ( e.value)
  {
    case MICROBIT_BUTTON_EVT_CLICK:         btnEvent = "CLICK";         break;
    case MICROBIT_BUTTON_EVT_DOUBLE_CLICK:  btnEvent = "DOUBLE_CLICK";  break;
    case MICROBIT_BUTTON_EVT_DOWN:          btnEvent = "DOWN";          break;
    case MICROBIT_BUTTON_EVT_HOLD:          btnEvent = "HOLD";          break;
    case MICROBIT_BUTTON_EVT_LONG_CLICK:    btnEvent = "LONG_CLICK";    break;
    case MICROBIT_BUTTON_EVT_UP:            btnEvent = "UP";            break;
  }

  uBit.serial.send( btnName + " " + btnEvent + "\n");
}


void onButtonA(MicroBitEvent e)
{
  ManagedString btnEvent;
  ManagedString btnName = "A ";

  switch ( e.value)
  {
    case MICROBIT_BUTTON_EVT_CLICK:         btnEvent = "CLICK";         break;
    case MICROBIT_BUTTON_EVT_DOUBLE_CLICK:  btnEvent = "DOUBLE_CLICK";  break;
    case MICROBIT_BUTTON_EVT_DOWN:          btnEvent = "DOWN";          break;
    case MICROBIT_BUTTON_EVT_HOLD:          btnEvent = "HOLD";          break;
    case MICROBIT_BUTTON_EVT_LONG_CLICK:    btnEvent = "LONG_CLICK";    break;
    case MICROBIT_BUTTON_EVT_UP:            btnEvent = "UP";            break;
  }

  uBit.serial.send( btnName + " " + btnEvent + "\n");
}


void onButtonB(MicroBitEvent e)
{
  ManagedString btnEvent;
  ManagedString btnName = " B";

  switch ( e.value)
  {
    case MICROBIT_BUTTON_EVT_CLICK:         btnEvent = "CLICK";         break;
    case MICROBIT_BUTTON_EVT_DOUBLE_CLICK:  btnEvent = "DOUBLE_CLICK";  break;
    case MICROBIT_BUTTON_EVT_DOWN:          btnEvent = "DOWN";          break;
    case MICROBIT_BUTTON_EVT_HOLD:          btnEvent = "HOLD";          break;
    case MICROBIT_BUTTON_EVT_LONG_CLICK:    btnEvent = "LONG_CLICK";    break;
    case MICROBIT_BUTTON_EVT_UP:            btnEvent = "UP";            break;
  }

  uBit.serial.send( btnName + " " + btnEvent + "\n");
}


void onButtonAB(MicroBitEvent e)
{
  ManagedString btnEvent;
  ManagedString btnName = "AB";

  switch ( e.value)
  {
    case MICROBIT_BUTTON_EVT_CLICK:         btnEvent = "CLICK";         break;
    case MICROBIT_BUTTON_EVT_DOUBLE_CLICK:  btnEvent = "DOUBLE_CLICK";  break;
    case MICROBIT_BUTTON_EVT_DOWN:          btnEvent = "DOWN";          break;
    case MICROBIT_BUTTON_EVT_HOLD:          btnEvent = "HOLD";          break;
    case MICROBIT_BUTTON_EVT_LONG_CLICK:    btnEvent = "LONG_CLICK";    break;
    case MICROBIT_BUTTON_EVT_UP:            btnEvent = "UP";            break;
  }

  uBit.serial.send( btnName + " " + btnEvent + "\n");
}


void togglePixel( int x, int y)
{
    uBit.display.image.setPixelValue( x, y, uBit.display.image.getPixelValue( x, y) ? 0 : 255);
}


void forever()
{
    while (true)
    {
        togglePixel( 0, 0);
        uBit.sleep(1000);
    }
}


int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    uBit.messageBus.listen( MICROBIT_ID_BUTTON_A,  MICROBIT_EVT_ANY, onButtonA);
    uBit.messageBus.listen( MICROBIT_ID_BUTTON_B,  MICROBIT_EVT_ANY, onButtonB);
    //uBit.messageBus.listen( MICROBIT_ID_BUTTON_AB, MICROBIT_EVT_ANY, onButtonAB);

    create_fiber( forever);

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

DAL PinMode not available

This will compile with DAL and fail with CODAL:

#include "MicroBit.h"

MicroBit uBit;

int  main() {
    uBit.init();
    uBit.io.P0.setPull(PullUp);
}
/Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/source/main.cpp: In function 'int main()':
/Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/source/main.cpp:8:30: error: no matching function for call to 'codal::NRF52Pin::setPull(PinMode)'
     uBit.io.P0.setPull(PullUp);
                              ^
In file included from /Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/libraries/codal-microbit-v2/model/MicroBitIO.h:29:0,
                 from /Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/libraries/codal-microbit-v2/inc/compat/MicroBitCompat.h:45,
                 from /Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/libraries/codal-microbit-v2/inc/MicroBitConfig.h:6,
                 from /Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/libraries/codal-microbit-v2/model/MicroBit.h:28,
                 from /Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/source/main.cpp:1:
/Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/libraries/codal-nrf52/inc/NRF52Pin.h:358:21: note: candidate: virtual int codal::NRF52Pin::setPull(codal::PullMode)
         virtual int setPull(PullMode pull) override;
                     ^~~~~~~
/Users/microbit-carlos/workspace/deleteme/really-delete/microbit-v2-samples/libraries/codal-nrf52/inc/NRF52Pin.h:358:21: note:   no known conversion for argument 1 from 'PinMode' to 'codal::PullMode'

Need to use PullMode::Up instead, but it's not DAL compatible.

Add hardware version to BLE device information service, model number string

Compared to the DAL, this repo's MicroBitBLEManager adds V2.0 to the device information service model number string. That is, "BBC micro:bit V2.0".

This is currently a fixed string, but should be based on an internal hardware version check, so that a hex created now could say, for example, V2.1 when loaded on a newer version of V2.

Touch pin triggered when mic casing is touched

Using a simple touch program in MakeCode:

https://makecode.microbit.org/_C0xg4ievw4C0

  1. Download program
  2. Touch logo. See face on display. Face clears
  3. Touch finger to mic casing on back of board. Logo touch is triggered

It isn't specifically the microphone casing that triggers the touch, but making a connection with components in that area.

VID_20210426_114953327.2.mp4

We raised this initially in
https://github.com/microbit-foundation/codal-microbit/issues/130 and the calibration was fixed for touching around the nRF52

Serial RX buffer overflow behaviour

When pasting enough text (example below) into tera term to overflow the buffer, this serial echo program, returns characters that are out of order. Subsequent single, typed characters (e.g. space) are echoed with characters from the pasted text. Buffering doesn't fail with the Mbed example.

serial-echo hex.zip

#include "MicroBit.h"

#ifdef CODAL_CONFIG_H
#define MICROBIT_CODAL 1
#else
#define MICROBIT_CODAL 0
#endif


MicroBit uBit;

int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    //uBit.sleep(2000);
    //if ( uBit.serial.isReadable())
    //  microbit_panic(888);

#if MICROBIT_CODAL
    uBit.serial.setBaudrate( 115200);
#else
    uBit.serial.baud( 115200);
#endif

    uBit.serial.setRxBufferSize( 250);
    uBit.serial.setTxBufferSize( 250);

    uBit.sleep(2000);
    if ( uBit.serial.isReadable())
      microbit_panic(999);

    while (true)
    {
      if ( uBit.serial.isReadable())
      {
          int c = uBit.serial.getc();
          if ( c >= 0)
              uBit.serial.putc( c);
          else
              uBit.serial.putc('?');
      }
      uBit.sleep(0);
    }

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

123456789A
123456789B
123456789C
123456789D
123456789E
123456789F
123456789G
123456789H
123456789I
123456789J
123456789K
123456789L
123456789M
123456789N
123456789O
123456789P
123456789Q
123456789R
123456789S
123456789T
123456789U
123456789V
123456789W
123456789X
123456789Y
123456789Z

123456789A
123456789B
123456789C
123456789D
123456789E
123456789F
123456789G
123456789H
123456789I
123456789J
123456789K
123456789L
123456789M
123456789N
123456789O
123456789P
123456789Q
123456789R
123456789S
123456789T
123456789U
123456789V
123456789W
123456789X
123456789Y
123456789Z

#include "mbed.h"

DigitalOut rows[5] = {
    DigitalOut(ROW_1, 0),
    DigitalOut(ROW_2, 0),
    DigitalOut(ROW_3, 0),
    DigitalOut(ROW_4, 0),
    DigitalOut(ROW_5, 0)
};
DigitalOut cols[5] = {
    DigitalOut(COL_1, 1),
    DigitalOut(COL_2, 1),
    DigitalOut(COL_3, 1),
    DigitalOut(COL_4, 1),
    DigitalOut(COL_5, 1)
};


Serial pc(USBTX, USBRX);

int main() {
    for ( int i = 0; i < 5; i++)
    {
      rows[i] = 1;
      cols[i] = 1;
    }

    pc.baud(115200);

    while (1)
    {
        if ( pc.readable())
        {
            cols[0] = 0;
            pc.putc( pc.getc());
        }
    }

    return 0;
}



Default pull mode seems different from V1, so getDigitalValue behaves differently

By default, V1 P0 reads 0 until connected to 3V, while V2 P0 reads 1 until connected to GND.

C++

#include "MicroBit.h"

MicroBit uBit;

int 
main()
{
    uBit.init();

    while(1)
      uBit.display.printCharAsync( uBit.io.pin[0].getDigitalValue() ? '1' : '0');
}

MakeCode

basic.forever(function () {
    basic.showNumber(pins.digitalReadPin(DigitalPin.P0))
})

CODAL Sleep power consumption display oddity

Currently the sleep power is slightly higher than it needs to be because of the way the display sleeps.

Putting in a ticket to track sleep power consumption in CODAL.

I think the most likely is that we're not parking the display pins 'disconnected' appropriately in all cases.

Configuring pin 16 for events stops events on all pins

The sample below works fully on V1, can see events on all the pins and switch between edge and pulse.

On V2:

  • If pin 16 is configured for events, none of the pins trigger events

  • If the first mode chosen is for edge events, it can't switch to pulse

// This tests pin events on pins 0,1,2,8 and 12-16.
// Press A for pulse; B for edge.
// Pixels light in columns 3 and 4 when events are detected.
// The pull mode is UP, so connect pins to GND to trigger events.

#include "MicroBit.h"

#ifdef CODAL_CONFIG_H
#define MICROBIT_CODAL 1
#else
#define MICROBIT_CODAL 0
#endif

MicroBit uBit;


void event_init_pin( int eventOn, int pinNumber);

void event_init_on( int eventOn)
{
    event_init_pin( eventOn, 0);
    event_init_pin( eventOn, 1);
    event_init_pin( eventOn, 2);
    event_init_pin( eventOn, 8);
    event_init_pin( eventOn, 12);
    event_init_pin( eventOn, 13);
    event_init_pin( eventOn, 14);
    event_init_pin( eventOn, 15);
    event_init_pin( eventOn, 16);
}


#if MICROBIT_CODAL
PullMode pullMode = PullMode::Up;
#else
PinMode  pullMode = PullUp;
#endif


bool eventHigh = false;
bool eventLow = false;

bool eventRise = false;
bool eventFall = false;


void onRise(MicroBitEvent e)
{
    eventRise = true;
}


void onFall(MicroBitEvent e)
{
    eventFall = true;
}


void onHi(MicroBitEvent e)
{
    eventHigh = true;
}


void onLo(MicroBitEvent e)
{
    eventLow = true;
}


void onButtonA(MicroBitEvent e)
{
    event_init_on( MICROBIT_PIN_EVENT_ON_PULSE);
}


void onButtonB(MicroBitEvent e)
{
    event_init_on( MICROBIT_PIN_EVENT_ON_EDGE);
}


void event_init_pin( int eventOn, int pinNumber)
{
    int pinID = MICROBIT_ID_IO_P0 + pinNumber;

    uBit.io.pin[ pinNumber].setPull( pullMode);

    uBit.io.pin[ pinNumber].eventOn( eventOn);

    uBit.messageBus.listen( pinID, MICROBIT_PIN_EVT_PULSE_HI, onHi);
    uBit.messageBus.listen( pinID, MICROBIT_PIN_EVT_PULSE_LO, onLo);

    uBit.messageBus.listen( pinID, MICROBIT_PIN_EVT_RISE, onRise);
    uBit.messageBus.listen( pinID, MICROBIT_PIN_EVT_FALL, onFall);
}


void event_init()
{
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB);
}


void event_fiber()
{
    while (true)
    {
        uBit.display.image.setPixelValue( 3, 0, eventHigh ? 255 : 0);
        uBit.display.image.setPixelValue( 3, 4, eventLow  ? 255 : 0);
        uBit.display.image.setPixelValue( 4, 0, eventRise ? 255 : 0);
        uBit.display.image.setPixelValue( 4, 4, eventFall ? 255 : 0);
        eventHigh = false;
        eventLow = false;
        eventRise = false;
        eventFall = false;
        uBit.sleep(200);
    }
}


void togglePixel( int x, int y)
{
    uBit.display.image.setPixelValue( x, y, uBit.display.image.getPixelValue( x, y) ? 0 : 255);
}


void forever()
{
    while (true)
    {
        togglePixel( 0, 0);
        uBit.sleep(1000);
    }
}


int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    event_init();
    create_fiber( event_fiber);

    create_fiber( forever);

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

evt.timestamp Zero on Codal

Same program run on V1 gives a reasonable event timestamp. On V2 it returns zero.

#include "MicroBit.h"
MicroBit uBit;
uint64_t timenow = 1;

void onPulseEdge(MicroBitEvent evt)
{
timenow = evt.timestamp;
uBit.io.P0.eventOn(MICROBIT_PIN_EVENT_NONE);
}

int main()
{
uBit.init();
uBit.io.P0.eventOn(MICROBIT_PIN_EVENT_ON_EDGE);
uBit.messageBus.listen(MICROBIT_ID_IO_P0, MICROBIT_PIN_EVT_RISE, onPulseEdge,
MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.serial.printf("Ready \n\r");
uBit.sleep(5000);
uBit.serial.printf("%d\n\r", (int)timenow);
}

Different V1/V2 behaviour of display.scroll / scrollAsync / printChar

If display.scroll is called while the screen is disabled V1 hangs whereas V2 continues.

In the test below, V2 sends "release_fiber\n", V1 doesn't.

// This tests the behaviour of scroll when the display is disabled.

#include "MicroBit.h"

MicroBit uBit;


int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    //Called here is OK
    //uBit.serial.send( "scroll before disable\n");
    //uBit.display.scroll("0");

    uBit.serial.send( "disable\n");
    uBit.display.disable();

    //When called here, V1 hangs, V2 continues
    uBit.serial.send( "scroll after disable\n");
    uBit.display.scroll("0");

    uBit.serial.send( "release_fiber\n");
    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

display.enable() doesn't re-configure the display pins

With this example the rightmost column (pin10) is turned on while printing the text:

#include "MicroBit.h"

MicroBit uBit;

int main() {
    uBit.display.disable();
    while (1) {
        uBit.sleep(250);
        uBit.io.P10.setAnalogValue(0);
        uBit.display.enable();
        uBit.display.print("Hello");
        uBit.display.disable();
    }
}

display.hex.zip

Floating pin reading as high (DAL has pull downs)

This programme in V1 DAL always reads the pin a floating pin as "low", until a jumper cable is used to connect it to the 3V pin.

#include "MicroBit.h"

MicroBit uBit;

int  main() {
    uBit.init();
    // uBit.io.P1.setPull(PullMode::Down);
    while (1) {
        if (uBit.io.P1.getDigitalValue() == 1) {
            uBit.display.printChar('H');
            uBit.sleep(400);
        } else {
            uBit.display.printChar('L');
            uBit.sleep(400);
        }
    }
}

The sleep is not required, it also shows that in V2 CODAL the first reading of the pin is always 0, as on reset it always it shows the L on the display once and then stays H.

Uncommenting the pull down matches the V1 DAL behaviour.

Tested P0,P1, P12, and P16, so I assume this is probably true for all io.

Pulsed events on V2 Hardware

Wasn't sure where to raise this. I've added a note to
microsoft/pxt-microbit#3731
However, on my V2 Microbit the pulse events aren't working. For examples

control.onEvent(EventBusSource.MICROBIT_ID_IO_P0, EventBusValue.MICROBIT_PIN_EVT_PULSE_HI, function () {
    led.toggle(0, 2)
})
control.onEvent(EventBusSource.MICROBIT_ID_IO_P0, EventBusValue.MICROBIT_PIN_EVT_PULSE_LO, function () {
    led.toggle(1, 2)
})
pins.setEvents(DigitalPin.P0, PinEventType.Pulse)
basic.forever(function () {
    if (pins.digitalReadPin(DigitalPin.P0) == 1) {
        led.plot(0, 0)
    } else {
        led.unplot(0, 0)
    }
})
basic.forever(function () {
    pins.digitalWritePin(DigitalPin.P1, 0)
    basic.pause(500)
    pins.digitalWritePin(DigitalPin.P1, 1)
    basic.pause(500)
})

The code works as expected on V1 hardware. Note, that if the event type is changed to edge detection, then that works fine on V1 & V2. So it looks like just the pulse is not working

V2 calibration does not persist on power cycles

Describe the bug
The compass calibration should persist through a power cycle/reset. This works on V1 boards, but not V2.

To Reproduce

  • Flash file the uses the compass
  • calibrate
  • power cycle

Expected behavior
Calibration persists unless flashed using drag and drop

See issue in MakeCode microsoft/pxt-microbit#3550 this reproduces in Python beta too

When the UART RX pin is grounded it can halt the user programme

By routing the UART pins to the edge connector, and then grounding the RX pin the display stops updating.

It doesn't look like it crashes, as usually that would leave a column/row light up.

In this example the text is scrolling and by tapping pin1 with a jumper cable to ground you can easily (not on the first tap, but you can try a few times) clear the display and nothing else seems to happen:

#include "MicroBit.h"

MicroBit uBit;

int  main() {
    uBit.init();

    uBit.serial.redirect(uBit.io.P0, uBit.io.P1);
    uBit.serial.setBaud(115200);

    while (1) {
        uBit.display.scroll("HELLO WORLD!", 400);
    }
}

uBit.serial.isReadable() always returns false unless uBit.serial.setRxBufferSize() is called

The program below echoes characters typed into tera term on Windows 10, but if the setRxBufferSize() call is removed, isReadable() always returns false.

#include "MicroBit.h"


MicroBit uBit;

void serial_fiber()
{
    uint8_t chr;

    // without setting the buffer, isReadable() never returns true

    uBit.serial.setRxBufferSize( 250);

    while (true)
    {
      if ( uBit.serial.isReadable())
      {
        //uBit.display.print('R');
        chr = '?';
        uBit.serial.read( &chr, 1);
        uBit.serial.send( &chr, 1);
      }

      uBit.sleep(0);
    }
}


void togglePixel( int x, int y)
{
    uBit.display.image.setPixelValue( x, y, uBit.display.image.getPixelValue( x, y) ? 0 : 255);
}


void forever()
{
    while (true)
    {
      togglePixel( 0, 0);
      uBit.sleep(1000);
    }
}


int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    create_fiber( forever);

    create_fiber( serial_fiber);

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

Build error on Ubuntu 20.04

Trying to build project on Ubuntu 20.04, using CMAKE 3.17 and having next error:

[main] Building folder: codal-microbit-v2 
[main] Configuring folder: codal-microbit-v2 
[proc] Executing command: /usr/local/bin/cmake --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -H/home/k2/Workbench/codal-microbit-v2 -B/home/k2/Workbench/codal-microbit-v2/build -G "Unix Makefiles"
[cmake] Not searching for unused variables given on the command line.
[cmake] -- Configuring incomplete, errors occurred!
[cmake] See also "/home/k2/Workbench/codal-microbit-v2/build/CMakeFiles/CMakeOutput.log".
[cmake] CMake Error at CMakeLists.txt:5 (RECURSIVE_FIND_DIR):
[cmake]   Unknown CMake command "RECURSIVE_FIND_DIR".

On power up, V2 sees garbage appear in uBit.serial.read buffer

Typically, after power up but not reset, a single random byte appears in the serial read buffer between uBit.systemTime()s 149 and 808.

On battery power, with no USB lead connected, the same thing happens, and sometimes I see 13 garbage bytes that take much longer appear.

serial-startup-hex.zip

#include "MicroBit.h"

#ifdef CODAL_CONFIG_H
#define MICROBIT_CODAL 1
#else
#define MICROBIT_CODAL 0
#endif

MicroBit uBit;

int serial_BAUDRATE = 115200;
//int serial_BAUDRATE = 57600;

MicroBitSerialMode serial_READMODE = ASYNC;
MicroBitSerialMode serial_SENDMODE = ASYNC;
//MicroBitSerialMode serial_SENDMODE = SYNC_SLEEP;

int serial_BUFFER_SIZE = ((uint8_t)250);


void serial_startup()
{
#if MICROBIT_CODAL
    uBit.serial.setBaudrate( serial_BAUDRATE);
#else
    uBit.serial.baud( serial_BAUDRATE);
#endif

    uBit.serial.setRxBufferSize( serial_BUFFER_SIZE);
    uBit.serial.setTxBufferSize( serial_BUFFER_SIZE);

    uint64_t t0 = uBit.systemTime();
    uint64_t t1 = 0;
    uint64_t t2 = 0;
    uint64_t tnow = 0;

    uint8_t store[1024];
    int count = 0;

    while ( tnow = uBit.systemTime(), tnow - t0 < 5000)
    {
        uint8_t buffer[serial_BUFFER_SIZE];
        int received = uBit.serial.read( buffer, serial_BUFFER_SIZE, serial_READMODE);
        if (received > 0)
        {
          if ( t1 == 0) t1 = tnow;
          t2 = tnow;

          if ( count + received < sizeof(store))
          {
            memcpy( store + count, buffer, received);
            count += received;
          }
        }
    }

    if ( count > 0)
    {
      uBit.display.scroll( ManagedString( count));
      uBit.display.scroll( ManagedString( (int)t1));
      uBit.display.scroll( ManagedString( (int)t2));

      uBit.serial.printf( "t0 %d t1 %d t2 %d count %d\n", (int)t0, (int)t1, (int)t2, count);

      for ( int i = 0; i < count; i++)
        uBit.serial.printf( "%x %d %c \n", (unsigned long) store[ i], (int) store[ i], (char) store[i]);
    }
}


int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    serial_startup();

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

New 'makeapp' flasher required for IoT applications

Currently this library is performing great for when you want a closed program running from a device created in Makecode but it is not working well at all for IoT applications! The difficulty is of course that BLE needs to bridge across to the internet and this communications is not well supported at the moment. There are various hardware attempts to add IoT support (proving need!) but they appear to be overcomplicating and overwhelming users with attaching various bits of hardware (WiFi,LoRa,Cellular etc.) and with mixing MQTT blocks and various things in makecode which is probably also an abstraction too far again!

I propose that we instead solve this problem with variations to the firmware (in codal) and software (adding a new 'makeapp' flashing environment). So how about we make a completely separate additional makecode type environment called 'makeapp'? There could be a https://makeapp.microbit.org/ store on the internet and also private makeapp stores running anywhere users want them ( e.g. https://makeapp.atmyschool.edu ) and can run a BLE bridge! The makeapp environment would save the current makecode users from being overwhelmed with options that are only required in client/server applications and this separation of concerns in dedicated environments would make it all so much easier to understand for users and massively extend the features and improve the usefulness of the project!

Also, if 'makeapp' existed and you wanted your Micro:bit to talk to IoT you don't need to attach anything to your device like now and it can just come fresh out the box and get attached by software! The difference would be that you flash it with the 'makeapp' flasher software rather than the 'makecode' flasher and that would open the BLE connection on the device specifically to speak with that IoT app. The IoT makecode apps would be things like 'vote on important world issues', 'vote on important things at school', 'get fit measure how I am doing and compete with friends', 'star wars co-op game with friends' etc.

The 'makeapp' environment could also be simple. You would only need to be able to subscribe to an app and establish a way with sharing the BLE, bind key, ids, tokens etc. to communicate over BLE with server. Then also just like with your phone APP you would need to choose and approve which sensors, actuators, gpio etc. you share with the it and how. There is also a huge area here for creativity here too and lets not forget that either... Even if your makeapp.microbit.org was just taking a 'yes' or 'no' vote from users they choose how to map it, whether to the buttons on the device, or some could attach foot switches to reduce COVID risks, or some could have shake or blow for yes or no or clap or anything they could imagine and build! This could also help improving accessibility in schools too as users could adapt micro:bits more widely to support user specific needs such as a physical or mental disability!

With this Micro:bits could be flashed by a new type of 'makeapp' HEX that exposes their BLE information and helps them communicate to IoT makeapp's in a standardized way. Then on the server side it would be much more straightforward to add the keys, tokens and IDs to read from the devices and what has been shared. This could easily be done server side in something like ESPhome BLE tracker (https://esphome.io/components/esp32_ble_tracker.html) for a couple of Micro:bits, or with bluez on Raspberry Pi for a class on in bluez in OpenWrt to service a whole school!

Garbage characters in UART RX buffer on power up

After a power up (but not reset) the UART RX buffer seems to be full of garbage (or at least unwanted) characters. And the number of garbage characters seems to be exactly the size of the RX buffer (eg 20 chars for the default size).

To reproduce:

int main() {
    uBit.init();
  
    const char *hexchr = "0123456789abcdef";
    for (;;) {
        int c = uBit.serial.read(SYNC_SPINWAIT);
        char str[60];
        memcpy(str, "RX(--)\r\n", 8);
        str[3] = hexchr[(c >> 4) & 0xf];
        str[4] = hexchr[c & 0xf];
        uBit.serial.send((uint8_t *)str, 8, SYNC_SPINWAIT);
    }

    return 0;
}

Running that on power up will usually show the issue (the microbit needs to be fully discharged before plugging in to USB to see the problem).

Attaching to the USB serial port after power up and pressing space many times I get the following output:

RX(03) <- this is printed when "space" is pressed the first time
RX(fd) <- this is printed when "space" is pressed the second time
RX(03)
RX(f5)
RX(21)
RX(02)
RX(00)
RX(47)
RX(89)
RX(e0)
RX(00)
RX(00)
RX(00)
RX(00)
RX(00)
RX(84)
RX(5e)
RX(00)
RX(20)
RX(db) <- this is the last garbage character in the 20-byte buffer
RX(20) <- this is printed when "space" is pressed the 21st time
RX(20)
RX(20)
RX(20)
RX(20)
RX(20)
...

I suspect this is the same as #45 but raised a separate issue because it's not just one garbage character but many (the size of the RX buffer), and doesn't need setRxBufferSize to trigger it.

Setting the serial tx buffer size to 255 "breaks" serial send

Because the codal-core driver adds one, overflowing the uint8_t:

int Serial::setTxBufferSize(uint8_t size)
{
    if(txInUse())
        return DEVICE_SERIAL_IN_USE;

    lockTx();

    // + 1 so there is a usable buffer size, of the size the user requested.
    this->txBuffSize = size + 1;

    int result = initialiseTx();

    unlockTx();

    return result;
}

Build error on Windows

I'm trying to get the samples built using Windows. I have install prerequisites - compiler, cmake, ninja, but get (when running the python script):
codal-microbit-v2 is already installed
Set target: codal-microbit-v2
Using target.json (dev version)
Targeting codal-microbit-v2
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
CMake Error at CMakeLists.txt:104 (project):
No CMAKE_C_COMPILER could be found.

The compiler is installed at its default location and I can't find the setting for CMake.
Any help much appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.