Microsoft MakeCode

How to deal with bitorder for SPI communication (MSB<->LSB)?

I guess, just like Mbed, that the micro:bit does MSB first for the communication. But is there an easy way to deal with LSB? I noticed that I was not able to use _rbit when I tried to use this as a C extrension. What would be the easy fix? A lookup table, but this likely wastes resources …

Look up table is only 256 bytes. You can put it in as a hex literal so it’s only stored in flash. If it’s not much data you can do it using bit operations but it may work out to be similar size when compiled.

A solution like:

let ReverseLookupTable =
    [
        0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
        0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
        ...
    ];

function BlahlaDoStuff() {
    let input = 0x42
    let output = BitReverseLookupTable[input]
    // output should be 0x42
}

would not work, as ading more netries will result in an error 84 or similar and that is likely caused by an out of memory. Each of these are likely claimed as a 32bit? So a lookup table does not fly if defined in TypeScript. Or … ?

Use hex literal like this:

1 Like

Ah, I see. Actually wanted to approach this as a buffer. Seems that would be taken care of:

Right. You need to use it like in the melody example above. The compiler treats these specially, similar to string literals, in that they are only stored in flash and do not occupy any RAM.

Probably a lot more of these gems exist in the platform…

I had looked at that code and noticed the NumberFormat option, etc. It made me wonder why there was no SPIWriteBuffer option (since I2C has).


const rbits = hex`
    008040C020A060E0109050D030B070F0088848C828A868E8189858D838B878F8
    048444C424A464E4149454D434B474F40C8C4CCC2CAC6CEC1C9C5CDC3CBC7CFC
    028242C222A262E2129252D232B272F20A8A4ACA2AAA6AEA1A9A5ADA3ABA7AFA
    068646C626A666E6169656D636B676F60E8E4ECE2EAE6EEE1E9E5EDE3EBE7EFE
    018141C121A161E1119151D131B171F1098949C929A969E9199959D939B979F9
    058545C525A565E5159555D535B575F50D8D4DCD2DAD6DED1D9D5DDD3DBD7DFD
    038343C323A363E3139353D333B373F30B8B4BCB2BAB6BEB1B9B5BDB3BBB7BFB
    078747C727A767E7179757D737B777F70F8F4FCF2FAF6FEF1F9F5FDF3FBF7FFF`

function rbit(input: number): number {
    return rbits.getNumber(NumberFormat.UInt8LE, input) || 0x00;
}

serial.writeLine("01 => " + rbit(0x01))
serial.writeLine("42 => " + rbit(0x42))
serial.writeLine("5a => " + rbit(0x5a))
serial.writeLine("ff => " + rbit(0xff))
serial.writeLine("00 => " + rbit(0x00))
serial.writeLine("fe => " + rbit(0xfe))

Note: will create an extension for this at http://github.com/gbraad/pxt-reversebit

There should be spi write buffer. I’ll look into that.

For your code it’s slightly more efficient to access the buffer directly via rbits[input] than with get number (only works for uint8)

I figured, as you essentially pick a byte… so you do not have to execute a subroutine.

But at the moment I can’t get a stable SPI clock from my library. Not sure what is happening …

There’s spiTransfer which is read and write combined. You can (and usually should) pass null as either of the buffers. I guess we should add spiRead and spiWrite - @peli what do you think?

For people less familiar with SPI - typically, in SPI there are separate lines for data going from master to slave (MOSI - master out slave in) and the other way around (MISO - master in slave out). These lines are meant to work at the same time, so when the master clocks the SCK line, for every bit, the master writes to MOSI and slave to MISO. This is why spiTransfer takes two buffers, and why the return value of spiWrite is the value read.

Typically most peripherals expect the master to write the command, possibly make a little break. Then the master is supposed to write zeros, while the slave writes the response, so there is no utilization of MISO and MOSI at the same time.

One can perform such a transaction with a single spiTransfer, by sending a buffer that starts with command and ends with padding, and getting back a buffer that starts with padding and ends with response. But most often what you will do, is to write the command with response == null, and then read the response with command == null in two spiTransfers.

s/spiRead/spiReadBuffer/
s/spiWrite/spiWriteBuffer/

Are you sure… not as part of the pins namespace at least.

Yeah, https://github.com/microsoft/pxt-common-packages/blob/master/libs/core/spi.ts#L33

I can haz it on Arcade, but not for the Micro:bit editor… :thinking:

makecode.microbit.org version:  2.0.17
Microsoft MakeCode version:  5.15.19
microbit runtime version:  pxtgc-0

Oh, right. Micro:bit is on legacy version of everything. We’re (or rather @peli is) trying to move it over to pxt-common-packages but this will take a while. Also, there’s no DMA for SPI master on micro:bit, so you may as well implement spiTransfer by running spiWrite in a loop.

Currently doing this… and the result is nasty. For some reason the clock is not stable (or almost non-existent) when probing with an analyzer.

Got it working: PS2 Controller extension

The extension can do rbit and rbuffer: https://github.com/gbraad/pxt-reversebit