Why does pyb.SPI.init() take a nondefaulted prescaler?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
kwiley
Posts: 140
Joined: Wed May 16, 2018 5:53 pm
Contact:

Why does pyb.SPI.init() take a nondefaulted prescaler?

Post by kwiley » Wed May 30, 2018 4:52 pm

According to https://docs.micropython.org/en/latest/ ... b.SPI.html the pyb.SPI init() function takes a prescaler parameter with no default value. It appears to work if none is provided (which I find a little confusing; shouldn't Python require a parameter for which no default value is provided? I realize there is a bare asterisk requiring named instead of positional args, but that shouldn't allow discarding a nondefaulted arg entirely), but even if it does work, I'm curious why no default is included when there is a default for practically every other parameter to that function? It feels like the docs don't reflect the actual underlying code (i.e., that some default actually is provided by the code even though the docs don't show it), but since the docs are surely machine generated, I can't believe that's the case.

Thanks.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Why does pyb.SPI.init() take a nondefaulted prescaler?

Post by dhylands » Wed May 30, 2018 6:25 pm

Well, it has a default value of 0xffffffff: https://github.com/micropython/micropyt ... #L584-L597

If you don't provide a prescaler then it dynamically calculates one which is appropriate for the baudrate. The value 0xffffffff is a value that you can't provide from the python side.

The pyb.SPI module is quite old and at the time it was written, I don't think it was possible to use None, which is how I would do it now if I were writing it.

If you're trying to write a generic function, then I would have the generic function take None as a default, and I would put the args into a dict, but don't store prescaler in the dict if it has a value of None and then pass the expanded dict to pyb.SPI constructor.

Code: Select all

>>> def generic_SPI(bus, mode, prescaler=None):
...     args = {}
...     if not prescaler is None:
...         args['prescaler'] = prescaler
...     spi = pyb.SPI(bus, mode, **args)
...     print(spi)
... 
>>> generic_SPI(1, pyb.SPI.MASTER)
SPI(1, SPI.MASTER, baudrate=328125, prescaler=256, polarity=1, phase=0, bits=8)
>>> generic_SPI(1, pyb.SPI.MASTER, prescaler=128)
SPI(1, SPI.MASTER, baudrate=656250, prescaler=128, polarity=1, phase=0, bits=8)
>>> generic_SPI(1, pyb.SPI.MASTER, prescaler=None)
SPI(1, SPI.MASTER, baudrate=328125, prescaler=256, polarity=1, phase=0, bits=8)

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Why does pyb.SPI.init() take a nondefaulted prescaler?

Post by pythoncoder » Fri Jun 01, 2018 7:05 am

@kwiley has a valid point - the docs are confusing. The following suggests that prescaler is a mandatory kwonly arg:
SPI.init(mode, baudrate=328125, *, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
Peter Hinch
Index to my micropython libraries.

kwiley
Posts: 140
Joined: Wed May 16, 2018 5:53 pm
Contact:

Re: Why does pyb.SPI.init() take a nondefaulted prescaler?

Post by kwiley » Fri Jun 01, 2018 9:06 pm

Yep. Thanks for considering the question.

Post Reply