New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safer behaviour when the mode of a pin changes. Fix up PWM implementation #345
Conversation
86c0943
to
c808edf
Compare
There are a lot of changes here.... what is the delta of code size and RAM usage? I see you needed to reduce the heap by about 150 bytes, and that's going to potentially break some large scripts. |
Hmm, Changes in RAM usage are going to be a nightmare, especially if user I know that the RAM utilisation story is complex, and especially Clearly the heap is one area we could set a high water mark on and signpost Actual runtime RAM utilisation of each feature is much harder to control. I Damien you're doing a great job to spot this, but it feels to me like there On 20 September 2016 at 05:11, Damien George notifications@github.com
|
c808edf
to
ecbb1c5
Compare
@dpgeorge Thanks for spotting the reduced heap size, I'd just chosen the lowest option when rebasing with the intention of fixing it up later, and then forgotten. Filesystem size will have reduced, but that's only temporary as this takes us very close to being able to drop the DAL. |
If we also drop mbed then we can reclaim a whole 2k of RAM, which would be the idea outcome. |
I plan to add a test-suite for this in the next few days. |
ecbb1c5
to
aecbd03
Compare
OK, I've added the test and it passes. |
6abee9f
to
f001119
Compare
@markshannon very nice work! I like that there are more "const" objects (ie less RAM usage) and that there's no longer a need for DAL Pin and Button, which take up lots of RAM. It seems that the code size actually decreases by about 500 bytes (probably due to less functions from DAL needed in the link stage). One point re the API: I think it should be allowed to do pin.write_digital even if the pin is in analog mode. There's no real need to force users to do pin.write_analog(0) then pin.write_digital(x). Also, please rebase :) |
@markshannon ping, see above comment. |
d2a7d93
to
3929ca4
Compare
Found some time to finish this at last. (No need to rebase, github can do that for us now) |
It's just as robust to add a new member to an enum, so I don't see a problem using ints here. Why expose the Regarding get/set pull: for the constants PULL_DOWN etc why not use the nrf register values directly? Then there is no need for a lookup table to convert between (-1,0,1) and the NRF_GPIO_PIN_xxx value. The values of these constants (exposed on the Python side) should anyway be opaque to the user, so it's ok to use the register values. And from a consistency point of view, if get_mode is going to be there in the API then it should be similar to get_pull, ie return an integer which corresponds to some constant. |
I should have been a bit clearer, it is not ints that are less robust than qstrs. It is using an external index which cannot be verified. Searching the array of modes, looking for a marker, whether it is a string or an int, is more robust than an unchecked indexing operation. Strings are also self describing. >>> p.get_mode()
"display" is a lot use informative than >>> p.get_mode()
7 The reason for using -1, 0, 1 rather than the nordic-defined constants is similar. |
To validate an index you just check that it's within a certain range (eg My other main point is that you don't need to expose pin.get_mode().
They are also opaque when getting. You should test against known values, eg |
You can't validate an index just by checking it is in range. E.g. enum {
DISPLAY_T,
SPEECH_T
};
pinmode_t modes = {
{ "speech", ... },
{ "display", ... },
}; which is awfully easy to do when adding new values to a larger array. |
It's possible to protect against incorrect ordering in an array using a C99 feature:
We use this quite a bit in uPy core. Well, anyway, if you want to keep the index as a qstr then I'm fine by it, especially since it's used to print a nicer error message.
The fact that you need an LUT at all. And there's extra translation code in get_pull() as well that you wouldn't need. |
I'd like to get this merged as it is blocking other work. I really don't think it is worth quibbling over a few bytes in a lookup table, as we will save kilobytes when we remove the superfluous parts of the DAL. |
The more bytes we save now the better. It's hard to take things away in the future (because users rely on them). I still think that making artificial pull values (-1, 0, 1) is not a good idea and wastes bytes. If I were a new user and did pin.get_pull() and got 0, I'd think it was pull down (since 0 is a low logic level). If I got -1 I'd be confused and think it was perhaps pulling it to a negative voltage. My proposal is as before: the constants What do other people think? |
Personally, I would expect |
Regarding @dpgeorge's question... I'm wearing my teacher's hat here - the most important thing is that it's obvious what's going on and that "what's going on" is related to current conventions and practices (so such skills and knowledge can be transferred). Given the above and upon careful reflection I prefer Damien's suggestion for the following reasons:
I hope this makes sense..? It would certainly make my life as a teacher and learner easier. Also, if what Damien says is true, it's more efficient in terms of memory. Just my 2c. :-) Happy to answer questions. |
@ntoll pin0.set_pull(pin0.PULL_DOWN)
pin1.set_pull(pin1.NO_PULL)
pin2.set_pull(pin2.PULL_UP)
print(pin0.get_pull(), pin1.get_pull(), pin2.get_pull()) I think it should be It looks like @ntoll has the deciding vote. Choose wisely 😄 |
Not exactly. What I'm saying is that the return value of pin.get_pull() is an opaque value and has no direct meaning to the user (they should not rely on it being anything sensible, it could even change from one version to the next). So it makes no sense to print it out. Instead, the things you can do with the return value are: 1) save it to a variable, 2) use it as an argument to pin.set_pull(), 3) compare it with the constants PULL_UP, PULL_DOWN, NO_PULL. The first question is: should pin.get_pull() return an opaque or transparent (ie user can take meaning from it) value? I vote opaque. If it's transparent, then the follow-up question is: what values should these transparent values be? |
I think we agree that the documentation should recommend that the user treats the value as opaque, It must have some value, and that value will be observable. |
What should the values be? I believe they should be obvious and unsurprising. Is there a precedent in this case? Are hardware engineers expecting the Nordic register values? It strikes me this may be a reasonable expectation. Alternatively, is there an existing numeric representation of pull up, pull down or no pull? If there isn't we should be careful: what value do we add by making one? We may even confuse people with a non-standard convention. On balance, if we use Nordic register value we can flag what this means in our documentation, we save a small amount of memory and we give learners an opportunity to ask, what exactly is a register value? Hope this makes (careful) sense. ;-) |
In this context, to me opaque means that it's not defined in the docs to be any particular value, the user should not rely on it being any particular value, and it can change at any notice and user code should not break. As such we're free to use any values, and using nordic register values is the simplest and most efficient (in code size and code execution). |
OK, I've changed the pull constants to be the nordic provided values. |
I've tacked the changes to the pull values to the final commit, so this PR should be squashed when merging. |
I don't see the changes...?
GtiHub only allows "squash all and merge" or "rebase and merge" (we want the latter). So If you want to have it squashed please do it on your branch corresponding to this PR. |
3929ca4
to
04e9f96
Compare
Make sure that PWM doesn't glitch when changing duty-cycle or period. Update music module to use PWM.
04e9f96
to
ce36e0d
Compare
Rebased, squashed and retested. |
It's done! |
Rework the pwm module to allow smooth transitions when period or duty cycles are changed.
Make music module use our pwm (not the DAL's pwm).
Modify the pin and related modules to ensure that attempting to use a pin when it is already used for another purpose, raises an exception.
For example:
Fixes #335, #337, #331, #288.