|
| 1 | +This directory shows the best practices for using MicroPython hardware API |
| 2 | +(`machine` module). `machine` module strives to provide consistent API |
| 3 | +across various boards, with the aim to enable writing portable applications, |
| 4 | +which would work from a board to board, from a system to another systems. |
| 5 | +This is inherently a hard problem, because hardware is different from one |
| 6 | +board type to another, and even from examplar of board to another. For |
| 7 | +example, if your app requires an external LED, one user may connect it |
| 8 | +to one GPIO pin, while another user may find it much more convinient to |
| 9 | +use another pin. This of course applies to relays, buzzers, sensors, etc. |
| 10 | + |
| 11 | +With complications above in mind, it's still possible to write portable |
| 12 | +applications by using "low[est] denominator" subset of hardware API and |
| 13 | +following simple rules outlined below. The applications won't be able |
| 14 | +to rely on advanced hardware capabilities of a particular board and |
| 15 | +will be limited to generic capabilities, but it's still possible to |
| 16 | +write many useful applications in such a way, with the obvious benefit of |
| 17 | +"write once - run everywhere" approach (only configuration for a particular |
| 18 | +board is required). |
| 19 | + |
| 20 | +The key to this approach is splitting your application into (at least) |
| 21 | +2 parts: |
| 22 | + |
| 23 | +* main application logic |
| 24 | +* hardware configuration |
| 25 | + |
| 26 | +The key point is that hardware configuration should be a separate file |
| 27 | +(module in Python terms). A good name would be `hwconfig.py`, and that's |
| 28 | +how we'll call it from now on. Another key point is that main application |
| 29 | +should never instantiate (construct) hardware objects directly. Instead, |
| 30 | +they should be defined in `hwconfig.py`, and main application should |
| 31 | +import and reference hardware objects via this module. The simplest |
| 32 | +application of this idea would look like: |
| 33 | + |
| 34 | +`hwconfig.py`: |
| 35 | + |
| 36 | + from machine import Pin |
| 37 | + |
| 38 | + LED = Pin("A3", Pin.OUT) |
| 39 | + |
| 40 | +`app.py`: |
| 41 | + |
| 42 | + from hwconfig import * |
| 43 | + import utime |
| 44 | + |
| 45 | + while True: |
| 46 | + LED.value(1) |
| 47 | + utime.sleep_ms(500) |
| 48 | + LED.value(0) |
| 49 | + utime.sleep_ms(500) |
| 50 | + |
| 51 | + |
| 52 | +To deploy this application to a particular board, a user will need: |
| 53 | + |
| 54 | +1. Edit `hwconfig.py` to adjust Pin and other hardware peripheral |
| 55 | + parameters and locations. |
| 56 | +2. Actually deploy `hwconfig.py` and `app.py` to a board (e.g. copy to |
| 57 | + board's filesystem, or build new firmware with these modules frozen |
| 58 | + into it). |
| 59 | + |
| 60 | +Note that there's no need to edit the main application code! (Which may |
| 61 | +be complex, while `hwconfig.py` should usually remain short enough, and |
| 62 | +focused solely on hardware configuration). |
| 63 | + |
| 64 | +An obvious improvement to this approach is the following. There're few |
| 65 | +well-known boards which run MicroPython, and most of them include an |
| 66 | +onboard LED. So, to help users of these boards to do configuration |
| 67 | +quickly (that's especially important for novice users, for who may |
| 68 | +be stumped by the need to reach out to a board reference to find LED |
| 69 | +pin assignments), `hwconfig.py` your application ships may include |
| 70 | +commented out sections with working configurations for different |
| 71 | +boards. The step 1 above then will be: |
| 72 | + |
| 73 | +1. Look thru `hwconfig.py` to find a section which either exactly |
| 74 | + matches your board, or the closest to it. Uncomment, and if any |
| 75 | + adjustments required, apply them. |
| 76 | + |
| 77 | +It's important to keep in mind that adjustments may be always required, |
| 78 | +and that there may be users whose configuration doesn't match any of |
| 79 | +the available. So, always include a section or instructions for them. |
| 80 | +Consider for example that even on a supported board, user may want to |
| 81 | +blink not an on-board LED, but the one they connected externally. |
| 82 | +MicroPython's Hardware API offers portability not just among "supported" |
| 83 | +boards, but to any board at all, so make sure users can enjoy it. |
| 84 | + |
| 85 | +There's next step of improvement to make. While having one `hwconfig.py` |
| 86 | +with many sections would work for smaller projects with few hardware |
| 87 | +objects, it may become more cumbersome to maintain both on programmer's |
| 88 | +and user's sides for larger projects. Then instead of single |
| 89 | +`hwconfig.py` file, you can provide few "template" ones for well-known |
| 90 | +boards: |
| 91 | + |
| 92 | +* `hwconfig_pyboard.py` |
| 93 | +* `hwconfig_wipy.py` |
| 94 | +* `hwconfig_esp8266.py` |
| 95 | +* etc. |
| 96 | + |
| 97 | +Then step 1 above will be: |
| 98 | + |
| 99 | +1. Look thru available `hwconfig_*.py` files and find one which matches |
| 100 | + your board the best, then rename to `hwconfig.py` and make adjustments, |
| 101 | + if any. |
| 102 | + |
| 103 | +Again, please keep in mind that there may be users whose hardware will be |
| 104 | +completely unlike you heard of. Give them some helpful hints too, perhaps |
| 105 | +provide `hwconfig_custom.py` with some instructions. |
| 106 | + |
| 107 | +That's where we stop with improvements to the "separate file for hardware |
| 108 | +configuration" idea, as it is already pretty flexible and viable. An |
| 109 | +application in this directory shows it in practice, using slightly less |
| 110 | +trivial example than just a blinking LED: `soft_pwm.py` implements a |
| 111 | +software PWM (pulse width modulation) to produce an LED fade-in/fade-out |
| 112 | +effect - without any dependence on hardware PWM availability. |
| 113 | + |
| 114 | +Note that improvements to board configuration handling may continue further. |
| 115 | +For example, one may invent a "configuration manager" helper module which will |
| 116 | +try to detect current board (among well-known ones), and load appropriate |
| 117 | +`hwconfig_*.py` - this assumes that a user would lazily deploy them all |
| 118 | +(or that application will be automatically installed, e.g. using MicroPython's |
| 119 | +`upip` package manager). The key point in this case remains the same as |
| 120 | +elaborated above - always assume there can, and will be a custom configuration, |
| 121 | +and it should be well supported. So, any automatic detection should be |
| 122 | +overridable by a user, and instructions how to do so are among the most |
| 123 | +important you may provide for your application. |
| 124 | + |
| 125 | +By following these best practices, you will use MicroPython at its full |
| 126 | +potential, and let users enjoy it too. Good luck! |
0 commit comments