Extending uLisp with SPI 16bit -> transfer16


#1

Hi David

Some SPI devices operate in 16bit spi.
I’ve seen in the arduino lib’s that there’s also a ‘transfer16()’
How do you feel about implementing it in ulisp ?
I was thinking something like (write-word ) and (read-word ).
I could use it for a realtime clock which works in 16bit spi.

Kind regards,
Ronny


#2

Hi Ronny,

Thanks for the suggestion. It seems that the SPI library’s transfer() and transfer16() functions are a bit different from uLisp’s read-byte and write-byte, as they do a simultaneous read and write.

Currently write-byte returns nil. Perhaps if called with an SPI stream it could return the result of transfer(), thus avoiding the need for another function? The same could be true of write-word for transfer16(). What do you think?


#3

Hi David,

Hi Ronny,

Thanks for the suggestion. It seems that the SPI library’s transfer() and transfer16() functions are a bit different from uLisp’s read-byte and write-byte , as they do a simultaneous read and write.

When writing a byte to a spi device it always returns something. So I think that this doesn’t make any difference. A write byte always gives reads back the result , although its useless of course.

Currently write-byte returns nil . Perhaps if called with an SPI stream it could return the result of transfer() , thus avoiding the need for another function? The same could be true of write-word for transfer16() . What do you think?

I think this is not so bad at all , since you can decide than what to do with the return (use it or not).

Regards ,
Ronny


#4

Hi David ,

I tried replacing spi.transfer with spi.transfer16 and it gave me a 16 bit stream on the clock and MOSI line !
The problem however , is that the high byte is always zero.
I think because of the char c in write-byte ?
Changing this to int c gives errors which I am not capable of solving .

How do you feel about it , for implementing in let’s say arm version ?
For avr I find it a bit to heavy , but maybe on arm it would be a nice thing to have.

Kind regards ,
Ronny


#5

I didn’t want to delay the release of Version 2.8 to incorporate this, so I’ll investigate how easy it will be to do, and if possible, include it in a future update.


#6

Ok , thanks .

Ronny


#7

Hi David,

I’ve started to use SPI devices and also wanted TRANSFER in addition to READ and WRITE. I didn’t want to change WRITE as you suggested as it would be quite unexpected that an output function suddenly doesn’t return the thing printed anymore but something else.

I just needed TRANSFER-BYTE and decided to just add that. I followed your pattern that you used for put and get and added a TFUN, a TSTREAMFUN, SPITRANSFER, and then fn_transferbyte / transfer-byte.

As transfer is implemented only for an SPI stream, TSTREAMFUN returns an error for all other streams.

So for SPI some output might be:

   (with-spi (lora *lora-ss-pin*)
     (list (transfer-byte (logand #x42 #x7f) lora)
           (transfer-byte 0 lora)))
   => (0 18)

But for other streams one gets:

(with-output-to-string (str) (transfer-byte 65 str))
=> Error: unknown stream type: transfer only supports SPI for now

Or even simpler:

(transfer-byte 65)
=> Error: unknown stream type: transfer only supports SPI for now

You’ll find the code as a diff in my repository at https://github.com/m-g-r/ulisp-esp-m5stack/commit/033051e40ecff188b1b44c3852c2b4cef92dba0c

Or at the bottom of this message.

Feel free to add it to the official uLisp release.

From Berlin,
Max

// transfer-byte for SPI by Max-Gerd Retzlaff <m.retzlaff@gmx.net>, 2023

typedef int (*tfun_t)(char);

// add ENDSPI to enum function

inline int spitransfer (char c) { return SPI.transfer(c); }

tfun_t tstreamfun (object *args) {
  int streamtype = SERIALSTREAM;
  int address = 0;
  tfun_t tfun = spitransfer;
  if (args != NULL && first(args) != NULL) {
    int stream = isstream(first(args));
    streamtype = stream>>8; address = stream & 0xFF;
  }
  if (streamtype == SPISTREAM) tfun = spitransfer;
  else error2(0, PSTR("unknown stream type: transfer only supports SPI for now"));
  return tfun;
}

object *fn_transferbyte (object *args, object *env) {
  (void) env;
  int value = checkinteger(TRANSFERBYTE, first(args));
  tfun_t tfun =  tstreamfun(cdr(args));
  int c = (tfun)(value);
  return (c == -1) ? nil : number(c);
}

const char string169b[] PROGMEM = "transfer-byte";

// add to const tbl_entry_t lookup_table[]:
  { string169b, fn_transferbyte, 0x12 },

#8

Thanks for that! (I’ve reformatted the listing.)


#9

Thanks! That looks better.

Also I should learn the new style of adding C functions and switch to uLisp 4.4+. I am still using 3.6b I am afraid. But when I also start using the Extensions File feature it might less work in the future to switch versions I assume. We’ll see.

Thanks for your work!
Max